Rails 2.2には多くの新機能と機能改善が盛り込まれています。このリストは主要なアップグレードをカバーしていますが、小さなバグフィックスや変更までは含まれていません。すべての変更を見るには、GitHubのRailsメインリポジトリのコミットリストを参照してください。
Rails 2.2のリリースに伴い、現在進行中のRails Guides hackfestの最初の成果であるRails Guidesが発表されました。Rails Guidesでは、Railsの主要な機能に関する高品質なドキュメントを提供する予定です。
Rails 2.2は、Railsを安定稼働させ、世界とつなぐインフラストラクチャとして重要なリリースです。
Rails 2.2では、国際化(internationalization: 長いのでi18nと略されます)向けの簡単なシステムが提供されます。
RailsがJRubyや次期Ruby 1.9とスレッド安全性に関してうまく動作するよう、多くの作業が行われました。Ruby 1.9のリリースはまだ先なので、Ruby 1.9でRailsを動かすのはまだ難しい状態ですが、Ruby 1.9がリリースされたときにRailsが移行する準備は整っています。
コードコメント形式のRails内部ドキュメントが随所で改善されました。また、Railsガイドプロジェクトは、Railsの主要なコンポーネントに関する決定的な情報源です。最初の公式リリースにはRailsガイドの以下のページが含まれています。
このガイドには、初級および中級Rails開発者向けの数万語におよぶガイドが用意されています。
ガイドをローカルで生成したい場合は、アプリケーションのディレクトリで以下を実行します。
$ rake doc:guides
これでガイドがRails.root/doc/guides以下に生成され、ブラウザでRails.root/doc/guides/index.htmlを開けばすぐに内容を表示できます。
HTTPヘッダでETagと最終更新タイムスタンプをサポートしたことで、最近更新されていないリソースへのリクエストをRailsが受け取ったときに空のレスポンスを返せるようになりました。これにより、レスポンスの送信が不要かどうかを確認できます。
class ArticlesController < ApplicationController def show_with_respond_to_block @article = Article.find(params[:id]) # リクエストで送信するヘッダがstale?に提供されたオプションと異なる場合、 # リクエストは実際にstaleし、respond_toブロックが起動する # (このときstale?呼び出しのオプションがレスポンスにセットされる)。 # リクエストヘッダがマッチする場合リクエストはフレッシュなのでrespond_toブロックはトリガーされない。 # 代わりにデフォルトのレンダリングが発生してlast-modifiedとetagヘッダーをチェックし、 # テンプレートをレンダリングする代わりに "304 Not Modified" だけを送信すればよいと判断する。 if stale?(:last_modified => @article.published_at.utc, :etag => @article) respond_to do |wants| # normal response processing end end end def show_with_implied_render @article = Article.find(params[:id]) # レスポンスヘッダを設定し、リクエストに対してそれらをチェックする。 # リクエストがstaleの場合(すなわちetagまたはlast-modifiedのいずれもマッチしない場合)、 # デフォルトのテンプレートレンダリングが行われる。 # リクエストがフレッシュな場合、デフォルトレンダリングはテンプレートをレンダリングする代わりに # "304 Not Modified "を返す。 fresh_when(:last_modified => @article.published_at.utc, :etag => @article) end end
Railsをスレッドセーフにするために行われた作業がRails 2.2に反映されています。Webサーバのインフラにもよりますが、これはメモリ内のRailsのコピー数が少なくても、より多くのリクエストを処理できることを意味し、サーバのパフォーマンス向上とマルチコアの利用率向上につながります。
アプリケーションのproductionモードでマルチスレッドディスパッチを有効にするには、config/environments/production.rbに以下の行を追加してください。
config.threadsafe!
ここでは、「トランザクショナルマイグレーション」と「プールされたデータベーストランザクション」という、2つの大きな追加機能について説明します。また、joinテーブル条件向けの新しい(そしてよりきれいな)構文の導入や、多くの小さな改良も行われました。
歴史的に、ステップを複数含むRailsマイグレーションはトラブルの元でした。マイグレーション中に何か問題が発生すると、エラー発生前のマイグレーションはデータベースを変更しますが、エラー発生後のマイグレーションは適用されません。また、マイグレーションのバージョンは実行済みとして保存されていたので、問題を解決した後にrake db:migrate:redoで単純に再実行できませんでした。トランザクショナルマイグレーションは、マイグレーションステップをDDLトランザクションでラップすることでこれを変更し、どれかが失敗したらマイグレーション全体を元に戻すようにします。Rails 2.2では、トランザクショナルマイグレーションは、PostgreSQLですぐにサポートされます。将来このコードは他のデータベースにも拡張可能で、IBMはすでにDB2アダプタをサポートするよう拡張しています。
コネクションプーリングは、Railsがデータベース接続のプールにデータベースリクエストを分散させ、最大サイズまで成長させられます(デフォルトでは5ですが、database.ymlにpoolキーを追加すれば調整できます)。これは、同時に多数のユーザーをサポートするアプリケーションのボトルネックを解消するのに役立ちます。また、wait_timeoutも用意されており、デフォルトでは5秒で終了します。ActiveRecord::Base.connection_poolは、必要に応じてプールに直接アクセスできます。
development: adapter: mysql username: root database: sample_development pool: 10 wait_timeout: 10
joinテーブル条件をハッシュで指定できるようになりました。これは、複雑なjoinをまたいでクエリを実行する必要がある場合に非常に有用です。
class Photo < ActiveRecord::Base belongs_to :product end class Product < ActiveRecord::Base has_many :photos end # 著作権フリーのproductをすべて取得する Product.all(:joins => :photos, :conditions => { :photos => { :copyright => false }})
Active Recordの動的finderファミリーに、新たに2つのメソッドが追加されました。
find_last_by_attributefind_last_by_attributeメソッドは、Model.last(:conditions => {:attribute => value})と同等です。
# ロンドンからユーザー登録した直近のユーザーを取得する User.find_last_by_city('London')
find_by_attribute!!付きの新しいfind_by_attribute!は、Model.first(:conditions => {:attribute => value}) || raise ActiveRecord::RecordNotFoundと同等です。マッチするレコードが見つからない場合は、nilを返す代わりに例外を発生します。
# 'Moby'がユーザー登録していなければActiveRecord::RecordNotFound例外を発生する User.find_by_name!('Moby')
Active Recordの関連付けプロキシは、プロキシされたオブジェクトのメソッドのスコープを尊重するようになりました。以前の@user.account.private_methodは、関連付けられたAccountオブジェクトのprivateメソッドを呼び出していました(User has_one :accountの場合)。この機能が必要な場合は、@user.account.send(:private_method)をお使いください(または、メソッドをprivateやprotectedではなくpublicにしてください)。method_missingをオーバーライドしている場合は、関連付けが正常に機能するようにrespond_toも同じ挙動になるようにオーバーライドする必要がある点にご注意ください。
rake db:migrate:redoにオプションでVERSIONを追加することで、redoで特定のマイグレーションを指定可能になりました。config.active_record.timestamped_migrations = falseと設定してください。:counter_cache => trueで宣言された関連付け)をゼロに初期化する必要がなくなりました。ActiveRecord::Base.human_nameにより、国際化に対応したモデル名を人間に読みやすく翻訳できるようになりました。コントローラ側では、ルーティングを整理するのに役立ついくつかの変更があります。また、複雑なアプリケーションのメモリ使用量を減らすために、ルーティングエンジンの内部にもいくつかの変更が加えられています。
ルーティングの「浅いネスト」は、ネストの深いリソースを使うときのよく知られた問題に対するソリューションを提供します。浅いネストでは、作業したいリソースを一意に識別するのに十分な情報だけを提供すれば済むようになりました。
map.resources :publishers, :shallow => true do |publisher| publisher.resources :magazines do |magazine| magazine.resources :photos end end
これで、以下のルーティングが認識されるようになります。
/publishers/1 ==> publisher_path(1) /publishers/1/magazines ==> publisher_magazines_path(1) /magazines/2 ==> magazine_path(2) /magazines/2/photos ==> magazines_photos_path(2) /photos/3 ==> photo_path(3)
新しいmemberルーティングやcollectionルーティングに対して、メソッドの配列を指定できるようになりました。これにより、複数のHTTP verbを処理する必要があるときに、任意のverbを受け取るようにルーティングを定義しなければならないという煩わしさから解放されます。以下はRails 2.2で有効なルート宣言です。
map.resources :photos, :collection => { :search => [:get, :post] }
デフォルトでは、map.resourcesを使ってルートを作成すると、Railsは7つのデフォルトアクション(index, show, create, new, edit, update, and destroy)に対するルーティングを生成します。しかし、これらのルーティングはそれぞれアプリケーションのメモリを消費し、Railsが追加のルーティングロジックを生成することになります。そこで、:onlyと:exceptオプションを使って、Railsがリソースに対して生成するルートを細かく設定できるようになりました。単一のアクション、アクションの配列、または特殊オプション:allや:noneを指定できます。これらのオプションは、ネストしたリソースに継承されます。
map.resources :photos, :only => [:index, :show] map.resources :products, :except => :destroy
config.action_controller.use_accept_header = trueでオンに戻せます。redirect_toがURIスキームを完全にサポートしました(たとえばssh: URIにリダイレクトできます)。renderが:jsオプションをサポートし、正しいMIMEタイプを持つ素のJavaScriptをレンダリングするようになりました。polymorphic_path([@project, @date, @area])をnilの日付で呼ぶと、project_area_pathが返されます。javascript_include_tagとstylesheet_link_tagが新しい:recursiveオプションをサポートし、:allも指定することでファイルのツリー全体を読み込めるようになりました。RJS#page.reloadは、ブラウザの現在のページをJavaScriptで再読み込みします。atom_feedヘルパーに:instructオプションが追加され、XML処理命令を挿入できるようになりました。Action Mailerがメーラーでレイアウトをサポートするようになりました。適切な名前のレイアウトを指定すると、HTMLメールをブラウザ上のビューのように整形できます。たとえば、CustomerMailerクラスはlayouts/customer_mailer.html.erbを使うことを想定しています。
Action Mailerは、GMailのSMTPサーバーでSTARTTLSを自動的にオンにすることで、ビルトインのサポートを提供するようになりました。このためには、Ruby 1.8.7がインストールされている必要があります。
Active Supportは、Railsアプリケーションのメモ化機能の組み込み、each_with_objectメソッド、委譲でのプレフィックスサポートなど、多くの新しいユーティリティメソッドを提供するようになりました。
メモ化(memoization)とは、あるメソッドを一度初期化した後、その値を保存して繰り返し使えるようにする手法です。自分のアプリケーションでこのパターンを使ったことがある人も多いでしょう。
def full_name @full_name ||= "#{first_name} #{last_name}" end
メモ化を使うと、このタスクを宣言的に処理できます。
extend ActiveSupport::Memoizable def full_name "#{first_name} #{last_name}" end memoize :full_name
その他のメモ化機能には、メモ化をオンオフできるunmemoize, unmemoize_all, memoize_allなどがあります。
each_with_objecteach_with_objectメソッドは、Ruby 1.9からバックポートされたメソッドを用いてinjectの代替となるメソッドを提供します。これはコレクションに対して反復処理を行い、現在の要素とメモをブロックに渡します。
%w(foo bar).each_with_object({}) { |str, hsh| hsh[str] = str.upcase } # => {'foo' => 'FOO', 'bar' => 'BAR'}
リードコントリビュータ: Adam Keys
あるクラスから別のクラスに振る舞いを委譲する場合、委譲されるメソッドで以下のようにプレフィックスを指定できるようになりました。
class Vendor < ActiveRecord::Base has_one :account delegate :email, :password, :to => :account, :prefix => true end
上はvendor#account_emailとvendor#account_passwordという委譲メソッドを生成します。また、以下のようにカスタムのプレフィックスも指定できます。
class Vendor < ActiveRecord::Base has_one :account delegate :email, :password, :to => :account, :prefix => :owner end
上はvendor#owner_emailおよびvendor#owner_passwordという委譲メソッドを生成します。
リードコントリビュータ: Daniel Schierbeck
ActiveSupport::Multibyteが大幅に更新されました。Ruby 1.9との互換性のための修正も含まれます。ActiveSupport::Rescuableが追加され、任意のクラスがrescue_from構文にミックスインできるようになりました。DateとTimeクラスにpast?, today?, future?が追加され、日付や時間を比較しやすくなりました。Array#[1]〜Array#[4]までのエイリアスとしてArray#second〜Array#fifthが追加されました。Enumerable#many?はcollection.size > 1をカプセル化したものです。Inflector#parameterizeは、入力をURLで利用可能な形に変換します(to_paramで使われます)。1.7.weeks.agoや1.5.hours.sinceのように認識できるようになりました。ActiveSupport::StringInquirerは、文字列が等しいかどうかをスマートにテストする方法を提供します(ActiveSupport::StringInquirer.new("abc").abc? => true)。Railties(Railsのコアコード)で最も大きな変更は、config.gemsの仕組みです。
config.gemsRailsアプリケーションで必要なすべてのgemsのコピーを/vendor/gemsに配置可能にすることで、デプロイの問題を回避し、Railsアプリケーションを自己完結性を高められるようになりました。この機能はRails 2.1で初めて登場しましたが、Rails 2.2ではより柔軟で堅牢になり、gems間の複雑な依存関係も扱えるようになりました。RailsのGem管理では以下のコマンドが使えます。
config.gem _gem名_: config/environment.rbファイルに対応するgemを設定rake gems: 設定済みのgemをすべて表示する。gem(および依存関係が)インストール済みか、frozenか、フレームワークgemかも表示されます(フレームワークgemは他のgemが実行されるよりも先に読み込まれ、frozenにできない)。rake gems:install: インストールされていないgemをインストールするrake gems:unpack: 必須gemのコピーを/vendor/gemsに配置するrake gems:unpack:dependencies: 必須gemのコピーと依存関係を/vendor/gemsに配置するrake gems:build: ビルドされていないネイティブ拡張をビルドするrake gems:refresh_specs: Rails 2.1で作成されたベンダリングgemをRails 2.2の保存方法に変える単一のgemをunpackまたはインストールする場合は、コマンドラインでGEM=_gem名_を指定します。
script/serverがThinを直接サポートするようになりました。script/plugin install <plugin> -r <revision>がsvnベースのプラグインと同様にgitベースのプラグインでも動作するようになりました。script/consoleで--debuggerオプションがサポートされました。rake notes:custom ANNOTATION=MYFLAGでカスタムアノテーションをリストアップできます。Rails.envがStringInquirerでラップされ、Rails.env.development?が使えるようになりました。今回のリリースで、一部の古いコードが非推奨化されました。
Rails::SecretKeyGeneratorはActiveSupport::SecureRandomに置き換えられました。render_componentは非推奨化されました。この機能が必要な場合はrender_components pluginを利用できます。パーシャルをレンダリングするときの暗黙のローカル代入が非推奨化されました。
def partial_with_implicit_local_assignment @customer = Customer.new("Marcel") render :partial => "customer" end
以前は、上記のコードで'customer'パーシャル内のcustomerというローカル変数が利用可能でした。現在は、すべての変数を明示的に:localsハッシュで渡す必要があります。
country_selectが削除されました。詳細および代替プラグインについては、http://www.rubyonrails.org/deprecation/list-of-countriesを参照してください(訳注: このページは現在無効です)。
ActiveRecord::Base.allow_concurrencyは無効になりました。
ActiveRecord::Errors.default_error_messagesは非推奨化されました。I18n.translate('activerecord.errors.messages')をお使い下さい。
%sと%dの式展開構文は国際化で非推奨化されました。
String#charsは非推奨化され、代わりにString#mb_charsが採用されました。
小数で表される月や年の長さが非推奨化されました。代わりに、RubyコアのDateクラスやTimeクラスの演算をお使いください。
Request#relative_url_rootは非推奨化されました。代わりにActionController::Base.relative_url_rootをお使いください。
リリースノート編集担当:Mike Gunderloy
Railsガイドは GitHub の yasslab/railsguides.jp で管理・公開されております。本ガイドを読んで気になる文章や間違ったコードを見かけたら、気軽に Pull Request を出して頂けると嬉しいです。Pull Request の送り方については GitHub の README をご参照ください。
原著における間違いを見つけたら『Rails のドキュメントに貢献する』を参考にしながらぜひ Rails コミュニティに貢献してみてください 🛠💨✨
本ガイドの品質向上に向けて、皆さまのご協力が得られれば嬉しいです。
Railsガイド運営チーム (@RailsGuidesJP)
Railsガイドは下記の協賛企業から継続的な支援を受けています。支援・協賛にご興味あれば協賛プランからお問い合わせいただけると嬉しいです。