Railsを使っている方も、使っていない方もこんにちは。この特集では、「 Rails2.0の足回りと中級者への道」と題して、2007年12月7日にリリースされたRails2.0の基礎と、Rails2.0が提示する新しいアプリケーションの形、について学んでいきたいと思います。
Rails2.0とは何か?
Railsの開発者David Heinemeier Hansson(DHH)自身が語るように、Rails2.0は「革命的というより漸進的(“ evolutionary rather than revolutionary” ) 」なリリースです。バージョンの数値の変化とはうらはらに、Rails1.1とRails1.2間に行われたほどの変革はありません。
ですが、痛みすら伴う数多くの洗練と、RESTfulなアプリケーションへの傾倒を含んだリリースになっています。
この特集ではまず、Rails2.0で行われた変化を探り、Rails2.0の香りを感じていきたいと思います。
Rails2.0の進化と変化
とはいうものの、Rails2.0での機能追加は、はじめてRailsに触れる人にとっては非常に細かな変化がほとんどです。「 Railsはじめまして」の方はしばらくご辛抱しておつきあいください。
ActiveRecord
Railsの中でももっとも大きく重要なフレームワークと目されているActiveRecordでも数多くの変更がなされました。
クエリーキャッシュ(Query Cache)
Rails2.0では、Railsの全てのactionの中で、自動でクエリーキャッシュが行われるようになりました。未設定の場合標準でクエリーキャッシュが行われます。
クエリーキャッシュとは、次のことをさします。
「SQLのSELECT文発行の結果を保持し、同じSQLが発行された場合はキャッシュの値を返すこと」
ただし、自動でクエリーキャッシュが行われるのは、Modelインスタンスの存続の間、通常は一つのリクエストの間に限られます。そのため複数のリクエストをまたぐようなキャッシュとしては利用できません。
キャッシュがクリアされるのは「INSERT、UPDATE、DELETEを発行したとき」です。結果が変更されてなくてもキャッシュはクリアされます。
実行時のイメージを、script/consoleで手動キャッシュを行うことで例示してみます。
リスト1 script/console
>> ActiveRecord :: Base . cache {
User . find ( 1 )
User . find ( 1 )
}
逆に、actionの中で、クエリーキャッシュを行いたく無い場合には以下のような工夫が必要です。
リスト2 app/model/user..rb
class User < ActiveRecord :: Base
class << self
def force_find (* args )
uncached { find (* args ) }
end
end
end
リスト2では、Userモデルに、force_findメソッドを追加しています。Rails2.0では、uncachedブロックを指定した場合のみ、キャッシュが行われません。
非キャッシュのfindを実行したい場合は以下のようになります。
リスト3 script/console
>> User . force_find (: all )
ActiveRecordその他の進化
その他の変更点としては、次のようなものが挙げられます。
数値のバリデーションが便利に
DBのスキーマ変更(マイグレーション)が簡単に(Sexy migration)
テスト用データの作成が簡単に(FoxyFixture)
開発の生産性を向上させるこれらの機能については、次回以降紹介していきたいと思います。
ActionPack(ActionController、ActionView、ActionHelper)
つづいて、ActionController、ActionView、ActionHelperの変化を見ていきます。
Custom Action Delimiter
まず、進化ではなく変化ですが、Rails2.0では、RESTfulなルートでのカスタムアクションの区切り文字が変更になりました。「 カスタムアクションの区切り文字」と言ってもピンとこない方も多いかと思います。具体例を挙げてみましょう。
リスト4 config/routes.rb
map . resource : posts , : collection =>{: comments => : get }
上のルート定義が行われていた場合、Rails1.2では、区切り文字として「;」が使われていました。
Rails2.0ではこれが「/」に変更になりました。
リスト5 Rails1.2
GET /posts;comments
リスト6 Rails2.0
GET /posts/comments
この変化の経緯は、『 W3C HTML4.01仕様書の附属書Bに「&」の代用として「;」のサポートを求める』 、HTTPサーバへの実装者への推奨からです。そのため素直に、そのとおり実装しているHTTPサーバもあるわけです。ですが、Rails1.2のカスタムアクションの区切りはこれを無視して「;」を区切り文字として使用していました。
ですので、この件についてはRails2.0での変化というより「行儀がよくなった」と言うべきかもしれません。既に、Rails1.2でRESTfulなアプリケーションを作成されている場合は注意が必要です。
RESTful Routing
Rails1.2以降、RESTfulなアプリケーションのためRoutingにさまざまな機能が追加されています。Rails2.0ではさらにいくつかの機能が採用になりました。
:name_prefixが不要に(自動でprefixがつきます)
namespace機能(ルーティングにネームスペースが追加可能に)
has_manyとhas_one Routing
ここでは、一番有用そうな、has_manyとhas_oneについて紹介したいと思います。
リスト7 Rails2.0
map . resources : articles ,
: has_many => [: comments , : tags ] ,
: has_one => : user
これは、Rails2.0以前の以下の記述と同じです。
リスト8
map . resources : articles do | article |
article . resources : comments
article . resources : tags
article . resource : user
end
ActiveRecordで、関連を作成する、:has_many、:has_oneの対応と意味的に同型であるため、Rails2.0以降は、Routingで:resources、:resourceを使い分けるのではなく、:has_many、:has_oneを利用する方が明解であると思います。
Rails1.2以降採用になった、RESTfulなRoutingは短いスペースで紹介するには非常に複雑な機能であるため、次回以降再度取り上げたいと思います。
部分レイアウト(Partial Layout)
これは、render:partialの中身にたいしてさらに:layoutを適用することができる、という機能です。
リスト9 app/views/links/show.html.erb
<% for link in @links do %>
<%= render : partial => 'link' ,
: layout => 'link_summary' ,
: locals => {: link => link } %>
<% end %>
上のコードが、メインとなるテンプレートです。ここで部分テンプレート(partial template)として、_link.html.erbを読み込んでいます。ここまではいままでどおりの部分テンプレートですが、見慣れない:layout指定があります。
この:layoutオプションで指定したレイアウトを適用し、部分テンプレートを表示します。
リスト10 app/views/links/_link.html.erb
<a href=" <%= link . url %> "> <%= link . title %></ a >
< div id = "comment" ><%= link . comment %></ div >
以下が、部分レイアウト(Partial Layout)です。ここで注意すべき点として、この部分レイアウトファイルは、app/views/layoutディレクトリではなく、コントローラ用のディレクトリに入れる必要があります。
リスト11 app/views/links/_link_summary.html.erb
<div id="link_ <%= link . id %> ">
<%= yield %>
</ div >
ActionPackその他の進化
そのほか、クライアントとサーバ間のレスポンスを向上させる以下の変更が組み込まれました。
画像用、CSS用といった複数のリソース用サーバがあるようにブラウザに思い込ませる(AssetServers)
複数のCSSや、Javascriptファイルを一つにまとめることで並列にダウンロードさせる(AssetCaching)
セッションの保持がRuby PStoreからクッキーに変更(Cookie-based Session)
Ajaxを縦横に用いた即時のレスポンスが必要なアプリケーションでは重宝する拡張であると思います。
rake
Rails自身の変化につづいて、Railsの補助ツールであるRailtiesの変化についてです。
Rails2.0では、開発時のさまざまな局面で助けとなる、rakeタスクが追加されました。
routes(Route Listing Task)
Rails1.2以降、RESTful対応でRailsのRoute情報は複雑化の一途をたどっています。
このタスクではその複雑さを少しでも軽減するため、config/routes.rbで設定した情報を可視化します。
リスト12
% rake routes|grep DELETE
DELETE /hellos/:id {:controller=>"hellos", :action=>"destroy"}
DELETE /hellos/:id.:format {:controller=>"hellos", :action=>"destroy"}
db:rollback
MigrationのバージョンをSTEP=Nで指定したNの分だけ過去に戻します。
リスト13
rake db:rollback STEP=1
Rails2.0以前は、このような相対的なバージョン指定ができなかったため、
現在のDBのバージョンを調べてから1減らした値を指定する、という面倒な作業を行う必要がありました。
Rails2.0以降では、db:rollbackを用いることでそういった局面での手数を減らすことができます。アジャイルなDB設計にとってはありがたい機能です。
notes:todo、notes:fixme
これはRails2.0で、ソースコードアノテーション(Source Code Annotations)といわれている機能です、コメント内のTODO、FIXMEと記述している箇所を一覧します。
リスト14
% rake notes:todo
app/controllers/hellos_controller.rb:
* [ 5] implement
RailsCoreからなくなったもの
最後に、Rails2.0でフレームワークのコアからなくなってしまった機能について触れておきます。
フレームワークのスリム化のため、さまざまな機能が、Rails2.0ではcoreからはずされ、外部プラグインになりました。
例を挙げると、scaffold、acts_as_*プラグイン、in_place_editing、auto_completeやデータベースアダプターなどです。ただし、外部プラグイン化したとは言え、これらのものについてはgemでインストールするか、
script/plugin installでインストールしていけば良いだけです。
それらとは異なり、それら以上に重要で、かつ代替手段に決定打が無いのが、Railsで複数ページ遷移の管理を行うPaginationの消失です。Rails2.0ではPagination機能が削除されました。Rails標準のプラグインとしても提供されず、サードパーティの機能を利用することになります。
この一点のみで、Rails2.0への移行が踏み切れないプロジェクトも多いのではないかと思います。2008年4月時点での代替手段の選択肢は、will_paginateプラグイン もしくは、paginating_findプラグイン です。
Rails2.0インストール
かけあしで、Rails2.0の進化と変化を紹介してきました。それでは、ごたくはこの辺にしまして、Rails2.0のインストールを行いましょう。
RubyGemsのインストール
まず、Rubyのパッケージ管理システムであるRubyGems をインストールします。メジャーなOS向けのパッケージが用意されていますので、ダウンロード、インストールしてください。
Rails2.0と必要なパッケージをインストール
RubyGemsのインストールが完了しましたら、gemを用い、Railsとその他必要なパッケージをインストールします。以下では、データベースアダプターとしてsqlite3、Railsのデバッグ用にruby-debugをインストールしています。
Rails2.0では標準のデータベースがsqlite3になっています。
リスト15
% gem install rails sqlite3 sqlite3-ruby ruby-debug
はじめての Rails2.0
それでは、すっかり有名になった Rails の scaffold を利用して、最初の Rails2.0 アプリケーション
を作ってみます。
Rails2.0のscaffoldは、Rails1.2でscaffold_resourceと呼ばれていたRESTfulなコードを出力するscaffoldです。そのため、初見の方や、従来のscaffoldから移行される方にはやや敷居の高いコードになっています。ですが、今回の特集の目的であるRESTfulなアプリケーションの作成のサンプルにはもってこいです。
リスト16
% rails hello
% cd hello
% ./script/plugin install scaffolding
% ./script/generate scaffold hello
% rake db:migrate
さてこれで準備はできました。
Railsアプリケーションをカスタマイズしていきましょう。
リスト17 app/controllers/hellos_controller.rb
def index
@greeting = "こんにちは"
@hellos = Hello . find (: all )
respond_to do | format |
format . html
format . xml { render : xml => @hellos }
end
end
こんどはViewを編集します。Rails2.0では、.rhtmlという拡張子と、.rxmlという拡張子が非推奨になりました。新しい拡張子はそれぞれ、.erb、.builderになります。Rails2.0では、.rhtml、.rxmlという拡張子もサポートされますが、今後のリリースではサポートが打ち切られれる可能性があります。Rails2.0のscaffoldでもVIEW用のテンプレートは.erbという拡張子のファイル名に変更されています。
index actionのなかに、あいさつを表示する、@greetingという変数を追加しています。
リスト18 app/views/hellos/index.html.erb
< h1 > Listing hellos </ h1 >
< table >
< tr >
< th > Message </ th >
< th ><%= @greeting %></ th >
</ tr >
<% for hello in @hellos %>
< tr >
< td ><%= h hello . message %></ td >
< td ><%= link_to 'Show' , hello %></ td >
< td ><%= link_to 'Edit' , edit_hello_path ( hello ) %></ td >
< td ><%= link_to 'Destroy' , hello , : confirm => 'Are you sure?' , : method => : delete %></ td >
</ tr >
<% end %>
</ table >
< br />
<%= link_to 'New hello' , new_hello_path %>
まとめと次回予告
以上、簡単ではありますが、Rails2.0の香りを感じてみました。次回からは、Rails2.0の機能の詳細を紹介しながら、RESTfulなウェブアプケーションを作っていきたいと思います。