Flex + Ruby (on Rails) でAMF通信とHTTP通信

クライアント側をFlexにし、サーバーをRailsで作成した通信に、
AMF通信とHTTP通信をそれぞれやってみました。

  • Railsプロジェクトを作成

Project Name : FlexServer
Use Database : sqlite3

rails FlexServer -d sqlite3

Rails Plugin : rubyAMF

ruby script/plugin install http://rubyamf.googlecode.com/svn/tags/current/rubyamf
  • rubyamf_config.rb の編集

> config/rubyamf_config.rb

ClassMappings.translate_case = true
ClassMappings.assume_types = true
  • 確認

サーバー起動

ruby script/server

http://localhost:3001/rubyamf/gateway

  • user の Controller/Model/View を生成

scaffold(rubyamf_scaffold もあるけど、今回は、利用せず)

ruby script/generate scaffold user
  • migration ファイルを修正

> db/migrate/xxxxxx_create_users.rb

def self.up
   create_table :users do |t|
     t.string :firstName
     t.string :lastName
     t.string :nickName
     t.integer :age, :limit => 3
     t.string :email, :default => 'anonymouse@gmail.com'
   ・・・・
  • DBとテーブルを生成
rake db:create
rake db:migrate
  • UsersControllerの編集

> app/controllers/users_controller.rb

def index
  @users = User.all
  respond_to do |format|
    format.html # index.html.erb
    format.xml  { render :xml => @users }
    format.amf  { render :amf => @users }
  end
end
  • mimeTypeの設定と修正

split ってメソッド を to_s に委譲(delegate)します(通信時エラーになるので)
> config/initializers/mime_types.rb

Mime::Type.register "application/x-amf", :amf
Mime::Type.delegate :split, :to => :to_s
  • crossdomain.xmlの設定

セキュリティエラーでるので。。
> public/crossdomain.xml

<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM 
                "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
    <site-control permitted-cross-domain-policies="all" />
    <allow-access-from domain="*" />
</cross-domain-policy>
  • UserList.mxmlの実装

最後に、FlexMXMLの実装
> src/UserList.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Application 
        xmlns:mx="http://www.adobe.com/2006/mxml"
        creationComplete="init()" 
        layout="absolute">
    
    <mx:Script>
        <![CDATA[
            import mx.rpc.http.HTTPService;
            import mx.rpc.events.FaultEvent;
            import mx.rpc.events.ResultEvent;
            
            private var amfFormat:Boolean;
            
            private function init():void {
                getAmfButton.addEventListener(MouseEvent.CLICK, getListForAmf);
                getHttpButton.addEventListener(MouseEvent.CLICK, getListForHttp);
            }
            
            // AMF通信
            private function getListForAmf(event:MouseEvent):void {
                this.amfFormat = true;
                
                var request:RemoteObject = this.userService;
                request.index();
                request.addEventListener(ResultEvent.RESULT, onResult);
                request.addEventListener(FaultEvent.FAULT, onFault);
            }
            
            // Web通信
            private function getListForHttp(event:MouseEvent):void {
                this.amfFormat = false;
                
                var request:HTTPService = new HTTPService();
                request.url = "http://localhost:3001/users.xml";
                request.resultFormat = HTTPService.RESULT_FORMAT_E4X;
                request.send();
                request.addEventListener(ResultEvent.RESULT, resultHandler);
                request.addEventListener(FaultEvent.FAULT, faultHandler);
            }

            private function resultHandler(event:ResultEvent):void {
                trace("onResult : " + event.result);
                if (amfFormat) {
                    userList.dataProvider = event.result;
                    msgLabel.text = event.result.toString();
                } else {
                    userList.dataProvider = event.result.user;
                    msgLabel.text = event.result.user.toString();
                }
            }

            private function faultHandler(event:FaultEvent):void {
                trace("onFault : " + event.fault);
                msgLabel.text = event.fault.faultString;
            }

        ]]>
    </mx:Script>
    
    <mx:RemoteObject id="userService"
                     destination="rubyamf"
                     endpoint="http://localhost:3001/rubyamf_gateway/"
                     source="UsersController" />

    <mx:VBox width="100%">
        <mx:DataGrid id="userList" width="100%">
            <mx:columns>
                <mx:DataGridColumn dataField="id" headerText="ID"></mx:DataGridColumn>
                <mx:DataGridColumn dataField="firstName" headerText="FirstName"></mx:DataGridColumn>
                <mx:DataGridColumn dataField="lastName" headerText="LastName"></mx:DataGridColumn>
                <mx:DataGridColumn dataField="age" headerText="Age"></mx:DataGridColumn>
                <mx:DataGridColumn dataField="nickName" headerText="NickName"></mx:DataGridColumn>
                <mx:DataGridColumn dataField="mail" headerText="Mail"></mx:DataGridColumn>
            </mx:columns>
        </mx:DataGrid>
        
        <mx:Button id="getAmfButton" label="Get for Amf" />
        <mx:Button id="getHttpButton" label="Get for Http" />
        
        <mx:Label id="msgLabel" />
    </mx:VBox>

</mx:Application>

Rails側のformatに対応したボタンをそれぞれ準備しました。
Rails側の

    format.amf  { render :amf => @users }

が、Flexの「Get for Amf」のボタンに対応し、

    format.xml  { render :xml => @users }

が、Flexの「Get for Http」のボタンに対応してます。

  • 実行

データを多く準備して、レスポンスを計測してみると、どちらが早いか検証できると思います。
やって見た方は、是非、レスポンスタイムとか教えて欲しいっす。