— boreal-kiss.com

Archive
Tag "Ruby"

Railsからの応答をE4Xで受信した場合とAMFで受信した場合を比較した。使ったのはidとnameからなる1000行のMySQLデータ。Flexからリクエストしてから応答までの時間を測定したところ、AMFの方が5倍も遅くなって困惑した。環境はFlex SDK 3.0, Ruby 1.8.6, Rails 2.1, MySQL 5.0.45で全て同じローカルマシン内。

Rails側

RubyAMFをインストールしたRailsプロジェクト内にUserモデルとUsersControllerを作成。UserモデルはMySQLのusersテーブル(id, name)とシンクロ済み(テストデータはgeneratedata.comで作成)。UsersControllerに以下のようにindexを記述。

class UsersController < ApplicationController

  def index
    @users = User.find(:all)    
    respond_to do |format|
      format.xml {render :xml => @users} # For HTTPService
      format.amf {render :amf => @users} # For RemoteObject
    end
  end
end

AMFの結果をArrayCollectionで簡単に受け取れるようrubyamf_config.rbを一部修正。ただしこの設定はRemoteObjectに対して有効で、NetConnectionではArrayCollectionが使えないため無効。

require 'app/configuration'
module RubyAMF
  module Configuration
    ClassMappings.assume_types = true
    ClassMappings.use_array_collection = true
  end
end

Flex側 (HTTPService – E4X)

load()とonResult()までの時間を10回測った。測定時間はTextAreaに、受信内容はDataGridにそれぞれ表示。

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

    <mx:HBox width="100%" height="100%">
        <mx:DataGrid id="dg" width="50%" height="100%">
            <mx:columns>
                <mx:DataGridColumn dataField="id"/>
                <mx:DataGridColumn dataField="name"/>
            </mx:columns>
        </mx:DataGrid>
        <mx:TextArea id="loadText" width="50%" height="100%"/>
    </mx:HBox>  
    <mx:Button label="Load" width="100" height="30" click="load(event)" />

    <mx:Script>
        <![CDATA[
            import mx.rpc.http.HTTPService;
            import mx.rpc.events.ResultEvent;
            import mx.rpc.events.FaultEvent;
            import flash.utils.getTimer;
            
            private var _start:uint;
            private var _str:String = "";
            
            private function load(e:Event):void{
                var req:HTTPService = new HTTPService();
                req.url = "http://127.0.0.1:3000/users.xml";
                req.resultFormat = HTTPService.RESULT_FORMAT_E4X;
                req.send();
                req.addEventListener(ResultEvent.RESULT,onResult);
                req.addEventListener(FaultEvent.FAULT,onFault);
                _start = getTimer();    
            }
            
            private function onResult(e:ResultEvent):void{
                dg.dataProvider = e.target.lastResult.user;
                _str += (getTimer() - _start).toString() + " msec\n";
                loadText.text = _str;
            }
            
            private function onFault(e:FaultEvent):void{
                loadText.text = e.fault.faultDetail;
            }
        ]]>
    </mx:Script>
</mx:Application>

Flex側 (RemoteObject – AMF)

MXMLの骨格はHTTPServiceを使う場合と同じ。スクリプト部分とservices-config.xmlの設定は以下の通り。

スクリプト部分

<mx:Script>
    <![CDATA[
        import mx.rpc.remoting.RemoteObject;
        import mx.rpc.events.ResultEvent;
        import mx.rpc.events.FaultEvent;
        import flash.utils.getTimer;
        
        private var _start:uint;
        private var _str:String = "";
        
        private function load(e:Event):void{
            var ro:RemoteObject = new RemoteObject();
            ro.source = "UsersController";
            ro.destination = "rubyamf";
            ro.index();
            ro.addEventListener(ResultEvent.RESULT,onResult);
            ro.addEventListener(FaultEvent.FAULT,onFault);
            _start = getTimer();
        }
        
        private function onResult(e:ResultEvent):void{
            dg.dataProvider = e.result;
            _str += (getTimer() - _start).toString() + " msec\n";
            loadText.text = _str;
        }
        
        private function onFault(e:FaultEvent):void{
            loadText.text = e.fault.faultString;
        }
    ]]>
</mx:Script>

services-config.xml (コンパイラオプションに追加)

<?xml version="1.0" encoding="UTF-8"?>
<services-config>
    <services>
        <service id="remoting-service" 
            class="flex.messaging.services.RemotingService" 
            messageTypes="flex.messaging.messages.RemotingMessage">
            <destination id="rubyamf">
                <channels>
                    <channel ref="ch-rubyamf" />
                </channels>
                <properties>
                    <source>*</source>
                </properties>
            </destination>
        </service>
    </services>
    
    <channels>
        <channel-definition id="ch-rubyamf" 
            class="mx.messaging.channels.AMFChannel">
            <endpoint uri="http://127.0.0.1:3000/rubyamf/gateway" 
                class="flex.messaging.endpoints.AMFEndpoint" />
        </channel-definition>
    </channels>
</services-config>

結果

HTTPService – E4X

load()からonResult()までの時間測定は右テキストエリア内(msec)。10回測定でだいたい0.5-0.6秒。ちなみにRESULT_FORMAT_OBJECT(ActionScript Object)で受信すると0.7-0.8秒ぐらいだった。

RemoteObject – AMF

HTTPServiceの場合と同じ測定で一回あたり約3秒。

AMF、通信設定が面倒なくせにすげー遅い。Ajax and Flex Data Loading Benchmarks | James Ward – RIA Cowboyの結果と違いすぎる。どっか間違ってる?

Read More

ソースコード HTML化 コンバーター「唐辛子」という非常に便利なアプリケーションがあるんですが、残念ながらRubyに対応していません。そこでRubyコード変換機能を追加したものをリリースしました。僕が使いたいというのが最大の理由なので必要最小限のプログラミング言語(Flex, ActionScript, JavaScript, Ruby, HTML, and XML)のみ変換可能です。その他の言語については本家をご利用ください。

Ruby唐辛子
[Flex]Ruby唐辛子

Rubyコードはこんな感じに表示されます。

  # POST /projects
  # POST /projects.xml
  def create
    @project = Project.new(params[:project])

    respond_to do |format|
      if @project.save
        flash[:notice] = 'Project was successfully created.'
        format.html { redirect_to(@project) }
        format.xml  { render :xml => @project, :status => :created, :location => @project }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @project.errors, :status => :unprocessable_entity }
      end
    end
  end

参考:

八角研究所 : Flex2でソースコードをブログに貼り付けるツールを作る(1) – ブログに美しいソースコードを貼り付けよう
八角研究所 : Flex2でソースコードをブログに貼り付けるツールを作る(2) – ソースコードをブログに貼り付けるツールを拡張しよう

Read More

データベースの情報をRailsでXMLファイルに整形しFlexに読み込ませる。Model-View-Controller(MVC)パターンで言うとMCをRailsに、VをFlexに担当させる。今までデータベースへのアクセスはPHPスクリプトを書いて行っていたが、Railsを用いるとその面倒くさいテンプレート書きが必要なくなるので非常に快適。用いたのはFlexSDK 3.0, Ruby 1.8.6, Rails 1.2.6, MySQL 5.0.5。Railsは最新の2.xを用いても特に問題ないと思う。以下の例ではデータベースに格納されたの本の詳細(title, price, description)をRailsで管理、FlexのGridDataに読み込ませている。

Rails側

Railsで適当なプロジェクト(ここではflex_connect)を作成。コマンドラインより

rails flex_connect

データベースを作成。MySQLコマンドラインより

mysql> create database flex_connect_development;

Railsプロジェクト内config/database.ymlを設定(今回はdevelopmentのみ使用)。

development:
  adapter: mysql
  database: flex_connect_development
  username: root
  password: [YOURPASSWORD]
  socket: /tmp/mysql.sock

次にモデルを作成(ここではBook)。Railsプロジェクト内に移動してコマンドラインより

ruby script/generate model Book

Railsプロジェクト内、db/migrate/xxx_create_books.rb(xxxの部分はrailsのバージョンによって異なる)を以下のように修正。

class CreateBooks < ActiveRecord::Migration
  def self.up
    create_table :books do |t|
      t.column :title, :string
      t.column :price, :float
      t.column :description, :text
    end
  end

  def self.down
    drop_table :books
  end
end

コマンドラインより

rake migrate

これによりDB: flex_connect_developmentにテーブルbooks(title, price, description)が作成される(MySQLを直接触らなくてよい!)。テーブル内に適当にテストデータを入力しておく(title=”Flex3″, price=”54.99″, description=”Adobe developer library”, etc.)。Railsから入力してやるのが簡単だがここでは割愛。

次にコントローラーを作成。コマンドラインより

ruby script/generate controller Book

Railsプロジェクト内、app/controllers/book_controller.rbに以下のメソッドを定義。

class BookController < ApplicationController
  def make_xml
    @books = Book.find(:all)
    render :xml => @books.to_xml
  end
end

これで”http://localhost:3000/book/make_xml”にアクセスするとデータベース情報がXML形式で出力される。例えばこんな感じ。

<?xml version="1.0" encoding="UTF-8"?>
<books>
  <book>
    <description>Ruby on Rails made easy.</description>
    <id type="integer">3</id>
    <price type="float">34.99</price>
    <title>Rails Solutions</title>
  </book>
  <book>
    <description>The Adobe developer library guide for rich interner application developers</description>
    <id type="integer">4</id>
    <price type="float">44.99</price>
    <title>Flex 3 Cookbook</title>
  </book>
  <book>
    <description>Friends of ED Adobe lerning library.</description>
    <id type="integer">5</id>
    <price type="float">54.99</price>
    <title>The Essential Guide To Flex 3</title>
  </book>
</books>

Flex側

“http://localhost:3000/book/make_xml”の内容をDataGridに表示させるソースは以下の通り。上記RailsのXMLファイルを出力するURLをロードしてDataGridに格納している。詳細は割愛。

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" 
                    layout="absolute" creationComplete="init(event)">
    
    <mx:DataGrid dataProvider="{_bookList}">
        <mx:columns>
            <mx:DataGridColumn dataField="title" />
            <mx:DataGridColumn dataField="price" />
            <mx:DataGridColumn dataField="description" />
        </mx:columns>
    </mx:DataGrid>

    <mx:Script>
        <![CDATA[
            import mx.collections.ArrayCollection;
            import mx.rpc.http.HTTPService;
            import mx.rpc.events.ResultEvent;
            import mx.rpc.events.FaultEvent;
            import mx.controls.Alert;
            import flash.net.URLRequestMethod;
            
            [Bindable]
            private var _bookList:ArrayCollection
            
            private function init(e:Event):void{
                var req:HTTPService = new HTTPService();
                req.url = "http://localhost:3000/book/make_xml";
                req.method = URLRequestMethod.POST;
                req.send();
                req.addEventListener(ResultEvent.RESULT,onResult);
                req.addEventListener(FaultEvent.FAULT,onFault);
            }
            
            private function onResult(e:ResultEvent):void{
                _bookList = e.result.books.book;
                e.target.removeEventListener(ResultEvent.RESULT,onResult);
                e.target.removeEventListener(FaultEvent.FAULT,onFault);   
            }
            
            private function onFault(e:FaultEvent):void{
                Alert.show("Could not connect the database.","ERROR");
                e.target.removeEventListener(ResultEvent.RESULT,onResult);
                e.target.removeEventListener(FaultEvent.FAULT,onFault);   
            }
        ]]>
    </mx:Script>
</mx:Application>

まとめ

今回はRails側にMVCパターンのMCを担当させた。同様にしてRails側のコントローラーに適切なメソッド(データの追加・削除 etc.)を追加することで専用のURLを簡単に作成できるので、Flex側は必要なURLにアクセスするだけでよくなった。

Read More

Ruby on Rails: Up And Running (Up and Running)

結論: Railsのバージョンの違いは致命的。この本は扱っているRailsのバージョンが1.1と古いので買うべからず。買うならRails 2.xと明記した最近の本を。

O’reillyでRuby on Railsを扱っている本がこれしかなかったので盲目的に買ったが失敗。扱ってるRailsのバージョンが古すぎて(1.x)、現行のRails 2.xだと四苦八苦することが多い。本自体は150ページと割と薄めで、一つのRailsアプリケーションを題材に進行していくため、(頭に入るかどうかは別として)よみすすめやすくはある。ただしRuby自体の教本ではないので(それほど親切に説明はない)Rubyのリファレンスは必要。僕は平行してThe Ruby Programming Languageを読んだ。

Railsのバージョンアップは初学者にはかなりの障壁になるようなので、もし手持ちの本がRails 1.xを扱っているようであれば、Railsのバージョンを落として学ぶか(仕組みを覚えてから2.xに移行)、2.xを扱う本を買った方が効率がよいと思う。以下Rails 1.x > 2.xの違いについて参考にしたページ。

追記 2008/08/08

レーダーチャートによる評価レビューはこちら

Read More