RailTrackrアプリケーション
RailTrackrは、ビジュアルリッチなWebベースのFlickrフォトブラウザです。このブラウザを使って、Rails 2.0の優れた機能を紹介します。サンプルアプリケーションを起動するには、本稿のサンプルコードをダウンロードし、通常のscript/serverコマンドを実行します。このアプリケーションはFlickrのAPIを使って写真を読み込むので、Flickr ServicesのサイトにAPIキーを要求し、そのキーをサンプルコードのflickr_helper.rbファイルに入力する必要があります。
このアプリケーションは、Flickrのユーザー、フォトセット、およびフォトセットに含まれる写真をナビゲートする方法を提供します。つまり、ここでは、FlickrUser、Photoset、Photoの3つのエンティティが定義されています。アプリケーションドメインでは、1つのFlickrUserに複数のPhotosetを割り当てることができ、各Photosetに複数のPhotoを割り当てることができます。これらがRailTrackrのRubyモデルになります。
Rails 2.0のRESTサポート
Rails 2.0の主な新機能の1つは、完全に「RESTful」であることです。REST(Representational State Transfer)のAPIに従うことでリソースの公開が非常に簡単になりました。実際、すべてのRailsモデル、もっと正確に言えば、アプリケーションのすべてのリソースを、HTTPプロトコルの基本コマンド(GET、POST、PUT、DELETE)を使って操作、アクセス、変更可能なオブジェクトとして公開できます。これらのコマンドは公開されるリソースに対するCRUD(Create、Read、Update、Delete)操作に直接マップされます。
RESTはRails 1.xでもすでにサポートされていましたが、さらに統合が進み、使いやすくなりました。RESTの原則に従ってリソースを公開するために必要なことは、写真リソースの操作に関する表1のようなメソッドを持つRailsコントローラを定義することだけです。
| コントローラのメソッド | CRUDの操作 | URL例 |
| index | すべての写真を取得する | GET /photos |
| show | ID 123の写真を取得する | GET /photos/123 |
| new | 新しい写真を取得して編集する | GET /photos/new |
| edit | ID 123の既存の写真を取得して編集する | GET /photos/123/edit |
| create | 新しい写真を作成(保管)する | POST /photos |
| update | 既存の写真123を更新する | PUT /photos/123 |
| destroy | 既存の写真123を削除する | DELETE /photos/123 |
RailTrackrで使用する最新のRails 2.0のスキャフォルドジェネレータは、常に表1のスキームに準拠するコントローラを作成します。script/generate scaffold Photoというコマンドを実行すると、次のファイルとエレメントが作成されます。
- RESTfulコントローラ(photos_controller.rb)
- ActiveRecordモデル(photo.rb)(サンプルアプリケーションでは、Flickr APIのプロキシに置き換えられます)
- 関連付けられたビュー(edit.html.erb、index.html.erb、new.html.erb、show.html.erb)
- ルーティングファイルroutes.rbの内側でのリソースマッピング
- テスト、フィクスチャ、データベース移行ファイルの通常のセット
以前のRailsバージョンと異なり、コントローラの名前は自動的に複数形になり、REST URLでのリソースのアドレス指定がより適切に反映されます。さらに、作成されるビューファイルの名前パターンがまったく新しくなりました。
多様なビュー
Rails 2.0では、マルチビューのサポートがテンプレートにまで拡張されています。それぞれ特定のエンジンでレンダリングされているリソースに、さまざまな形式でアクセスし操作することができます。ビューのファイル名構文は[name_of_the_view].[format].[engine]です。たとえば、show.html.erbというファイルは、次の処理を実行します。
- コントローラのshowメソッドに関連付けられたビューを表現します。
- html出力を生成します。
- erb(Embedded Ruby)エンジンを使います(erbは以前のRailsバージョンで動的なHTMLビューの作成に使われたデフォルトエンジンです)。
したがって、たとえばshow.csv.erbテンプレートとshow.atom.builderテンプレートは、同じビューをそれぞれerbで生成されたCSV(Comma Separated Value)形式のコンテンツと、XMLビルダエンジンで生成されたATOMシンジケーションフィードにマップします。
コントローラはrequest.format関数とrespond_to関数を使って、レンダリング形式の変更と実行フローの適切なテンプレートへの転送をそれぞれ行うことができます。指定がない場合、Railsは要求されたリソースのMIMEタイプに従って適切なテンプレートを検出します。次のリストに、コントローラのメソッドが写真のリストをHTMLページまたはXMLファイルのいずれかとして返す方法を示します。
class PhotosController < ApplicationController # GET /photos # GET /photos.xml def index @photos = # load photos from Flickr respond_to do |format| format.html # index.html.erb format.xml { render :xml => @photos } end end end
RailTrackrは、ユーザーが具体的な画像を要求した場合は必ずJPGバイナリ画像として写真をレンダリングします。この要件に対応するには、コントローラのshowメソッドを次のように変更する必要があります。
class PhotosController < ApplicationController # ... omissis ... # GET /photos/1.jpg def show @photo = Photo.find(params[:id]) respond_to do |format| format.jpg end end end
次に、ビューファイルviews/photos/show.jpg.erbを作成する必要があります。このファイルが画像のバイナリコンテンツを出力します。
<%= @photo.image_data %>
モデルオブジェクト@photoには、画像そのもののバイナリコンテンツを含む属性image_dataがあります。
デフォルトの形式(HTML、XML、ATOMなど)のほかに、ファイルconfig/initializers/mime_types.rbを編集してMime::Type.register_alias関数を使うことでカスタムの形式を作成する方法もあります。この機能を示す有効な構成は次のとおりです。
# Bind jpeg mime-type to the format.jpg format Mime::Type.register_alias "image/jpeg", :jpg # Bind the richtext mime-type to the format.rtf format Mime::Type.register "text/richtext", :rtf # Bind an additional formatter to the html mime-type, to be used # for mobile devices with a limited display Mime::Type.register_alias "text/html", :mobile
最後の行で、2つの異なるHTMLレンダリング(ブラウザ用と、ディスプレイ機能が限定されたモバイルデバイス用)を用意するという一般的な要件を満たしています。コントローラは、要求パラメータまたはHTTPヘッダに応じて適切なレンダリングを選択できます。次にその例を示します。
class PhotosController < ApplicationController before_filter :detect_mobile_device def index @photos = # load photos from Flickr respond_to do |format| format.html # index.html.erb format.mobile # index.mobile.erb end end ... omissis ... def detect_mobile_device if request.env['HTTP_USER_AGENT'] && request.env['HTTP_USER_AGENT'][/BlackBerry/] request.format = :mobile end end end
カスタムの形式を使ってモバイルデバイスをサポートする方法については、このチュートリアルを参照してください。
リソースのネストによるわかりやすいURLの作成
ここまでは、次のようなRESTのURLに基づいてリソースを提供するRailTrackrの機能を説明しました。
- http://yoursite.com/flickr_users/max ― Flickrユーザーmaxの詳細を表示します。
- http://yoursite.com/photosets/123 ― ID 123のフォトセットを表示します。
- http://yoursite.com/photos/456/edit ― ID 456の写真を編集します。
実際に、routes.rbファイル内の基本的なリソースマッピングを見ると、スキャフォルドコマンドが次のエントリを作成したことがわかります。
ActionController::Routing::Routes.draw do |map| map.resources :photos map.resources :photosets map.resources :flickr_users # default mapping map.connect ':controller/:action/:id' map.connect ':controller/:action/:id.:format' end
Rails 2.0には、URLを改善してわかりやすくする方法が用意されています。ActiveRecordモデルで1対多の関係を構成する方法と同様に、リソース間のマッピングを宣言して、次のようなURLを使ってリファレンス間をナビゲートできるようになりました。
- http://yoursite.com/flickr_users/max/photosets ― maxのすべてのフォトセットを表示します。
- http://yoursite.com/photosets/123/photos ― フォトセット123に含まれるすべての写真を表示します。
これらのURLには、覚えやすい自然な名前が付けられています。これらのURLを有効にするために必要なステップは2つだけです。まず、次のコンテンツを反映するようにroutes.rbを変更します。
ActionController::Routing::Routes.draw do |map| map.resources :flickr_users map.resources :flickr_users, :has_many => :photosets map.resources :photosets, :has_many => :photos # default mapping map.connect ':controller/:action/:id' map.connect ':controller/:action/:id.:format' end
その後、次のようにユーザーとそのフォトセット間のリソースマッピングを宣言してコントローラを編集します。
class PhotosetsController < ApplicationController before_filter :load_user # Given a sample url like site.com/flickr_user/max/photosets , # params[:flickr_user_id] automagically points to 'max' def load_user @flickr_user = FlickrUser.find(params[:flickr_user_id]) end # GET /photosets def index @photosets = Photoset.by_user(@flickr_user)[0..50] respond_to do |format| format.html # index.html.erb end end end
before_filterステートメントにより、フォトセットにアクセスする前にそのフォトセットのユーザーが読み込まれます。flickr_user_id変数には、Railsによって自動的に、親リソース(flickr_user)の名前から命名規約に従って値が設定されます。
このネストリソースマッピングは、コントローラ内だけでなく、ビュー内でのURLの生成にも使うことができます。たとえば、@flickr_userはID maxのユーザーを参照し、@photosetはID 123のフォトセットを参照しているとします。次のすべてのステートメントをビュー内で正しく使うことで、link_toなどのリンク関数に関連付け可能なURLを生成できます。
- flickr_user_photosets_url(@flickr_user)は、www.site.com/flickr_user/max/photosets(ユーザーのすべてのフォトセットのリスト)を参照します。
- flickr_user_photoset_url(@flickr_user,@photoset)は、www.site.com/flickr_user/max/photoset/123(1つの特定のフォトセットの詳細)を参照します。
- photoset_photos_url(@photoset)は、www.site.com/photosets/123/photos(フォトセット123に含まれるすべての写真)を参照します。
