まずはrailsのバージョンアップ

%gem install rails

config/environment.rbを書き換えて、ファイル構成をアップデート

%rake rails:update

と思ったけれども、諸々の事情により、新たにアプリケーションを作成し、app,lib,public,config,venderの内容をコピー
ようやくサーバが立ち上がる。が、render_componentがなくなっている。

%ruby script/plugin install git://github.com/rails/render_component.git

プラグインのインストールを試みるものの、

undefined method `set_session_options'

となってしまった。仕方ないので取りあえずバージョンを2.2.2にしたらサーバは立ち上がった。

次にDB関係。初期の頃はmigrationファイルが無いので、schema.rbを出力して最初から作り直す。

%rake db:schema:dump

すべてのテーブルを作成を最初のmigrationファイルで生成するよう、schema.rbの内容をコピペ

ruby script/generate migration InitialSchema

でrb:migrateしようとすると、ドライバがないっていわれる。。。

sudo gem install mysql

でインストールしても何かが足りない。Googleで調べると、↓でいけた。

sudo gem install mysql -- --with-mysql-config=/opt/local/lib/mysql5/bin/mysql_config

長い戦いになりそうだ。。。

メモ

  • Rackって?RackでCGI周りが変わったのかWebOrbやら、jpmobileやらが動かない。Rails2.2なら動く
  • environment.rbにグローバル定数を定義するようなことはできなくなったのかな。
  • リリースノートはちゃんと読もう。

(WebOrbをRails2.2.2で動かすにあたって、init.rbの30行目を若干変更)

  -Dependencies.mechanism = :load
  +ActiveSupport::Dependencies.mechanism = :load

5月末までにやりたいことリスト

現在運用しているRailsアプリケーションについて、5月末までにやりたいこと。

  • バージョンが1.2.6を2.3.2にアップグレード
  • RSpecの導入およびテストケースの充実
  • サーバをAmazonEC2に移行
  • Capistranoの導入
  • 新機能をいくつかついか

果たしてどこまでできますか。。。

Adobe MAXに参加

したので超カンタンにメモ。内容は適当です。

基調講演
テーマ3つ
・client + cloud
AIRで作ったInternational Herald Tribuneのリーダー。組版がなかなかすてき。
・social computing
パーティの招待状を送るwebサイトとAIRアプリの連携(だったと思う)
データがpushされるのがすてきなくらいかな。。。
・device + desktop
ここが一番面白かった。docomoの端末でAIRを動かすデモ。アルバムの編集を他のPCユーザーと共同でできたりする。
これが本当ならCocoa touch覚えなくてもActionScriptで携帯アプリつくれるじゃん!と思ったら、まだ検討段階だそうで。

ほかのセッション

・Flex4の紹介
サーバーサイドとの連携がカンタンにできるようになりそうだったが、ちょっと型から外れることすると大変そう。
ネットワークのパフォーマンスモニタができるといっていたがデモはなかった。
他はまー普通

・新テキストエンジン「Text Layout FrameWork」のTips
これはすごい。カンタンに新聞記事のような画面が作れそう。後で遊ぶ。

AIR最適化テクニック
これは役に立つ
下記3つのテーマで。

  • execute

型付けはコストが高い
ArrayよりByteArrayでもVectorが一番いいかな
RegExpは遅いっす。
AMFは結構余計なことをしちゃう(らしい?)
MXMLタグは階層を深くしない方がよい

  • memory management

んーメモが読めない。

  • rendering

creationPolicyはqueuedが良い。
alpha=0はvisible=falseと違うよ。
とか諸々。
こちらに資料があるらしい。
Craftymind | Hacking away at UI development

・詳説Flexコンポーネント
コンポーネントが生成される動作を詳しく解説。意外に分かっていかったことが発覚。

capistranoの認証で秘密鍵を指定する

ちょっとはまったのでメモ
deploy.rbに下記を記述

set :user, "foo"
ssh_options[:keys] = %w(/home/foo/.ssh/id_rsa)

参考:http://www.edit.ne.jp/~koic/wiki/?Capistrano

追記

subversionで認証をかけている場合

set :scm_user,"ユーザー名"
set :scm_password,"パスワード"
#set :scm_password, Proc.new { Capistrano::CLI.password_prompt("SVN password for #{scm_user}, please: ") }
set :repository, Proc.new { "--username #{scm_user} --password #{scm_password} --no-auth-cache リポジトリのパス" }

Weborbプラグインにキャッシュを実装する。その1[flex+Rails]

Weborbにキャッシュ機能を追加したみた際のメモ。まずはソースの解析から。すいません、図は正確でないです。

Weborbの全体像

WeborbはflexRails間でAMF通信する機能を提供する。
大まかに分けると、requestのパース、実行ロジックへのディスパッチ、responseメッセージの組み立ての3つの部分からなる。
なお、weborbのデータ構造は下記のようなクラス図になっている。受信メッセージがReqMessage、返信用メッセージがAckMessageクラスで、それらをRequestクラスが保持している。requestをパースした結果、ReqMessageオブジェクトが生成される。ディスパッチャがReqMessageの内容に応じて実行ロジックを起動し、返信用のAckMessageをReqMessageオブジェクトから受け取る。AckMessageの内容をAmfVFomtterを使って返信用のバイト列を生成していく、というのが大まかな流れ。


解析〜実行

下のシーケンス図はWeborbでメッセージがパースされ、返信用のデータを保持するAckMessageが生成されるまで流れをあらわしている。

まず受け取ったrequestのバイト列をパーサに渡し、Requestオブジェクトを生成する。Requestオブジェクトが持つReqMessageクラスには起動すべきクラス、メソッドが格納されている。次に、v3dispatcherクラスがRequestからReqMessageを取り出してexecuteメソッドを実行する。ReqMessageは保持している属性から指定の実行ロジックを実行し、実行結果を格納したAckMessageオブジェクトを生成する。v3dispatcherクラスはAckMessageをRequestのbodyに格納する。ここまでが解析から実行までのながれである。

responseメッセージの生成

下図のシーケンス図は実行結果として生成したAckMessageに基づき、返信メッセージが生成する流れをあらわしている。

まずRequestオブジェクトからAmfV3Formtterオブジェクトを取得する。このオブジェクトに返信用のバイト列を次々に書き込むことで、返信メッセージが生成される。
Weborbはまず、ResponseWriterにReqeustオブジェクトとAmfV3Formatterオブジェクトを渡す。ResponseWriterはバージョン情報など、静的な情報を書き込んだ上で、RequsetオブジェクトからAckMessageオブジェクトを取り出しMessageWriterに渡す。MessageWriterは渡されたデータのクラスに応じてformatterにデータに書き込むクラスである。まずAckMessageがデータとして渡されるため、ObjectWriterが呼び出される。
ObjectWriterはObjectをハッシュにしてObjectSerializerに渡す。そしてObjectSerializeがキーをformatterに書き込み、値を引数に再度MessageWriterを読み出す。こうすることで、AckMessageをトップとして、属性値が文字や数字まで分解されるまでObjectWriterを再帰的に呼び出すことができる。最後にAmfV3Formtterに書き込まれたバイト列を取り出して返信する。

キャッシュ化の方針

キャッシュを実装するためには、下記3つの機能が必要になる。(多分)

  1. キャッシュ対象のリクエストの選別
  2. キャッシュ対象データをPersistanceなオブジェクトに保存
  3. 再度リクエスト対象が来た場合に処理をバイパスし、Persinstanceなオブジェクトからデータを取り出して返信用のデータを生成

ちょっと時間がなくなってしまったので、上の3つをどう実装したかは日を改めてメモする。

Railsとflexの連携にWebOrbを使っていて気づいたことのメモ。

DBの属性として定義している項目などは、flex側で同じ名前のプロパティを用意しておけば自動的に受け取れる。では、メソッドの実行結果も渡したいときにどうすればよいか。チュートリアルを読んでもわからなかった。普通に実行すると、いちいち通信する必要がある。なので仕方なくソースを読んでみた。多分この辺が関係してそう。
(weborb/lib/writer/message_writer.rbの185行目付近)

  def MessageWriter.write_active_record( data_object, formatter )
    properties = data_object.attributes
    instance_variables = data_object.instance_variables
    instance_variables.each do |instance_variable|
      method_name = instance_variable.delete "@"
      next if(method_name == "attributes" or method_name == "new_record" or method_name == "new_record_before_save" or method_name == "errors" )
      if data_object.respond_to?( method_name )
        method = data_object.method method_name
        model_data = method.call
        properties.store( method_name, model_data )
      else
        Log.debug( "active record object does not respond to the method: " + method_name ) if Log.debug?
      end
    end
    
    object_class = data_object.class
    attributes = object_class.get_attributes
	attributes.each do |attribute|
	  attr_name = attribute.id2name
	  attr_method = data_object.method attr_name
	  attr_value = attr_method.call
	  properties.store( attr_name, attr_value )
	end

    class_name = data_object.class.name
    server_mappings = WebORBConfig.get_server_mappings
    resolved_name = server_mappings[class_name]
    
    if resolved_name.nil?
      MessageWriter.write_hash( properties, formatter )
    else
      object_serializer = formatter.get_object_serializer
	  object_serializer.write_object( resolved_name, properties, formatter )
    end
  end
end

インスタンス変数かアクセサとして定義してあれば、メソッドの実行結果が代入されるっぽい。以下のようにしてみたら、flex側でメソッドの実行結果を利用できた(discount_priceが実行結果を送付したいメソッド名)。もっとちゃんとした方法がありそうだけど。

require 'weborb/context'
require 'rbconfig'
class AMFProduct
   def getProduct(params)
     params = params.with_indifferent_access
     product = Product.find(params[:id])
     product.instance_variable_set("@discount_price",nil)
     product
   end
end