Ruby on Rails 2.2 リリースノート

Rails 2.2には多くの新機能と機能改善が盛り込まれています。このリストは主要なアップグレードをカバーしていますが、小さなバグフィックスや変更までは含まれていません。すべての変更を見るには、GitHubのRailsメインリポジトリのコミットリストを参照してください。

Rails 2.2のリリースに伴い、現在進行中のRails Guides hackfestの最初の成果であるRails Guidesが発表されました。Rails Guidesでは、Railsの主要な機能に関する高品質なドキュメントを提供する予定です。

1 インフラストラクチャ

Rails 2.2は、Railsを安定稼働させ、世界とつなぐインフラストラクチャとして重要なリリースです。

1.1 国際化

Rails 2.2では、国際化(internationalization: 長いのでi18nと略されます)向けの簡単なシステムが提供されます。

1.2 Ruby 1.9およびJRubyとの互換性

RailsがJRubyや次期Ruby 1.9とスレッド安全性に関してうまく動作するよう、多くの作業が行われました。Ruby 1.9のリリースはまだ先なので、Ruby 1.9でRailsを動かすのはまだ難しい状態ですが、Ruby 1.9がリリースされたときにRailsが移行する準備は整っています。

2 ドキュメント

コードコメント形式のRails内部ドキュメントが随所で改善されました。また、Railsガイドプロジェクトは、Railsの主要なコンポーネントに関する決定的な情報源です。最初の公式リリースにはRailsガイドの以下のページが含まれています。

このガイドには、初級および中級Rails開発者向けの数万語におよぶガイドが用意されています。

ガイドをローカルで生成したい場合は、アプリケーションのディレクトリで以下を実行します。

$ rake doc:guides

これでガイドがRails.root/doc/guides以下に生成され、ブラウザでRails.root/doc/guides/index.htmlを開けばすぐに内容を表示できます。

3 HTTPとの統合を改善: すぐ利用できるETagサポート

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

4 スレッド安全性

Railsをスレッドセーフにするために行われた作業がRails 2.2に反映されています。Webサーバのインフラにもよりますが、これはメモリ内のRailsのコピー数が少なくても、より多くのリクエストを処理できることを意味し、サーバのパフォーマンス向上とマルチコアの利用率向上につながります。

アプリケーションのproductionモードでマルチスレッドディスパッチを有効にするには、config/environments/production.rbに以下の行を追加してください。

config.threadsafe!

5 Active Record

ここでは、「トランザクショナルマイグレーション」と「プールされたデータベーストランザクション」という、2つの大きな追加機能について説明します。また、joinテーブル条件向けの新しい(そしてよりきれいな)構文の導入や、多くの小さな改良も行われました。

5.1 トランザクショナルマイグレーション

歴史的に、ステップを複数含むRailsマイグレーションはトラブルの元でした。マイグレーション中に何か問題が発生すると、エラー発生前のマイグレーションはデータベースを変更しますが、エラー発生後のマイグレーションは適用されません。また、マイグレーションのバージョンは実行済みとして保存されていたので、問題を解決した後にrake db:migrate:redoで単純に再実行できませんでした。トランザクショナルマイグレーションは、マイグレーションステップをDDLトランザクションでラップすることでこれを変更し、どれかが失敗したらマイグレーション全体を元に戻すようにします。Rails 2.2では、トランザクショナルマイグレーションは、PostgreSQLですぐにサポートされます。将来このコードは他のデータベースにも拡張可能で、IBMはすでにDB2アダプタをサポートするよう拡張しています。

5.2 コネクションプール

コネクションプーリングは、Railsがデータベース接続のプールにデータベースリクエストを分散させ、最大サイズまで成長させられます(デフォルトでは5ですが、database.ymlpoolキーを追加すれば調整できます)。これは、同時に多数のユーザーをサポートするアプリケーションのボトルネックを解消するのに役立ちます。また、wait_timeoutも用意されており、デフォルトでは5秒で終了します。ActiveRecord::Base.connection_poolは、必要に応じてプールに直接アクセスできます。

development:
  adapter: mysql
  username: root
  database: sample_development
  pool: 10
  wait_timeout: 10

5.3 joinテーブル条件でハッシュを利用可能に

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 }})

5.4 新しい動的finderメソッド

Active Recordの動的finderファミリーに、新たに2つのメソッドが追加されました。

5.4.1 find_last_by_attribute

find_last_by_attributeメソッドは、Model.last(:conditions => {:attribute => value})と同等です。

# ロンドンからサインアップした直近のユーザーを取得する
User.find_last_by_city('London')
5.4.2 find_by_attribute!

!付きの新しいfind_by_attribute!は、Model.first(:conditions => {:attribute => value}) || raise ActiveRecord::RecordNotFoundと同等です。マッチするレコードが見つからない場合は、nilを返す代わりに例外を発生します。

# 'Moby'がサインアップしていなければActiveRecord::RecordNotFound例外を発生する
User.find_by_name!('Moby')

5.5 関連付けがprivateやprotectedスコープを尊重するようになった

Active Recordの関連付けプロキシは、プロキシされたオブジェクトのメソッドのスコープを尊重するようになりました。以前の@user.account.private_methodは、関連付けられたAccountオブジェクトのprivateメソッドを呼び出していました(User has_one :accountの場合)。この機能が必要な場合は、@user.account.send(:private_method)をお使いください(または、メソッドをprivateやprotectedではなくpublicにしてください)。method_missingをオーバーライドしている場合は、関連付けが正常に機能するようにrespond_toも同じ挙動になるようにオーバーライドする必要がある点にご注意ください。

5.6 その他のActive Recordの変更

  • rake db:migrate:redoにオプションでVERSIONを追加することで、redoで特定のマイグレーションを指定可能になりました。
  • UTCタイムスタンプの代わりに数値のプレフィックスを持つ移行を行うにはconfig.active_record.timestamped_migrations = falseと設定してください。
  • カウンタキャッシュのカラム(:counter_cache => trueで宣言された関連付け)をゼロに初期化する必要がなくなりました。
  • ActiveRecord::Base.human_nameにより、国際化に対応したモデル名を人間に読みやすく翻訳できるようになりました。

6 Action Controller

コントローラ側では、ルーティングを整理するのに役立ついくつかの変更があります。また、複雑なアプリケーションのメモリ使用量を減らすために、ルーティングエンジンの内部にもいくつかの変更が加えられています。

6.1 ルーティングの浅いネスト

ルーティングの「浅いネスト」は、ネストの深いリソースを使うときのよく知られた問題に対するソリューションを提供します。浅いネストでは、作業したいリソースを一意に識別するのに十分な情報だけを提供すれば済むようになりました。

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)

6.2 Method Arrays for Member or Collection Routes

新しいmemberルーティングやcollectionルーティングに対して、メソッドの配列を指定できるようになりました。これにより、複数のHTTP verbを処理する必要があるときに、任意のverbを受け取るようにルーティングを定義しなければならないという煩わしさから解放されます。以下はRails 2.2で有効なルート宣言です。

map.resources :photos, :collection => { :search => [:get, :post] }

6.3 特定のアクションを持つresources

デフォルトでは、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

6.4 その他のAction Controllerの変更

  • リクエストのルーティング中に発生した例外で、カスタムエラーページを簡単に表示できるようになりました。
  • HTTP Acceptヘッダはデフォルトで無効化されました。Acceptヘッダが必要な場合は、config.action_controller.use_accept_header = trueでオンに戻せます。
  • ベンチマークが秒単位ではなくミリ秒単位で出力されるようになりました。
  • RailsがHTTPonly cookieをサポートするようになりました(セッションで使われます)。これは新しいブラウザでクロスサイトスクリプティングのリスクを軽減するのに有用です。
  • redirect_toがURIスキームを完全にサポートしました(たとえばssh: URIにリダイレクトできます)。
  • render:jsオプションをサポートし、正しいMIMEタイプを持つ素のJavaScriptをレンダリングするようになりました。
  • リクエストフォージェリ対策がHTMLフォーマットのコンテンツリクエストにのみ適用されるように強化されました。
  • 渡されたパラメータがnilの場合のポリモーフィックURLの振る舞いが改良されました。たとえば、polymorphic_path([@project, @date, @area])をnilの日付で呼ぶと、project_area_pathが返されます。

7 Action View

  • javascript_include_tagstylesheet_link_tagが新しい:recursiveオプションをサポートし、:allも指定することでファイルのツリー全体を読み込めるようになりました。
  • 同梱のPrototype JavaScriptライブラリがバージョン1.6.0.3にアップグレードされました。
  • RJS#page.reloadは、ブラウザの現在のページをJavaScriptで再読み込みします。
  • atom_feedヘルパーに:instructオプションが追加され、XML処理命令を挿入できるようになりました。

8 Action Mailer

Action Mailerがメーラーでレイアウトをサポートするようになりました。適切な名前のレイアウトを指定すると、HTMLメールをブラウザ上のビューのように整形できます。たとえば、CustomerMailerクラスはlayouts/customer_mailer.html.erbを使うことを想定しています。

Action Mailerは、GMailのSMTPサーバーでSTARTTLSを自動的にオンにすることで、ビルトインのサポートを提供するようになりました。このためには、Ruby 1.8.7がインストールされている必要があります。

9 Active Support

Active Supportは、Railsアプリケーションのメモ化機能の組み込み、each_with_objectメソッド、委譲でのプレフィックスサポートなど、多くの新しいユーティリティメソッドを提供するようになりました。

9.1 メモ化

メモ化(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などがあります。

9.2 each_with_object

each_with_objectメソッドは、Ruby 1.9からバックポートされたメソッドを用いてinjectの代替となるメソッドを提供します。これはコレクションに対して反復処理を行い、現在の要素とメモをブロックに渡します。

%w(foo bar).each_with_object({}) { |str, hsh| hsh[str] = str.upcase }
# => {'foo' => 'FOO', 'bar' => 'BAR'}

リードコントリビュータ: Adam Keys

9.3 委譲でのプレフィックス指定

あるクラスから別のクラスに振る舞いを委譲する場合、委譲されるメソッドで以下のようにプレフィックスを指定できるようになりました。

class Vendor < ActiveRecord::Base
  has_one :account
  delegate :email, :password, :to => :account, :prefix => true
end

上はvendor#account_emailvendor#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

9.4 その他のActive Supportの変更

  • ActiveSupport::Multibyteが大幅に更新されました。Ruby 1.9との互換性のための修正も含まれます。
  • ActiveSupport::Rescuableが追加され、任意のクラスがrescue_from構文にミックスインできるようになりました。
  • DateTimeクラスにpast?, today?, future?が追加され、日付や時間を比較しやすくなりました。
  • Array#[1]Array#[4]までのエイリアスとしてArray#secondArray#fifthが追加されました。
  • Enumerable#many?collection.size > 1をカプセル化したものです。
  • Inflector#parameterizeは、入力をURLで利用可能な形に変換します(to_paramで使われます)。
  • 日数や週数の端数を1.7.weeks.ago1.5.hours.sinceのように認識できるようになりました。
  • 付属のTzInfoライブラリがバージョン0.3.12にアップグレードされました。
  • ActiveSupport::StringInquirerは、文字列が等しいかどうかをスマートにテストする方法を提供します(ActiveSupport::StringInquirer.new("abc").abc? => true)。

10 Railties

Railties(Railsのコアコード)で最も大きな変更は、config.gemsの仕組みです。

10.1 config.gems

Railsアプリケーションで必要なすべての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名_を指定します。

10.2 その他のRailtiesの変更

  • Thin Webサーバのファンに朗報です。script/serverがThinを直接サポートするようになりました。
  • script/plugin install &lt;plugin&gt; -r &lt;revision&gt;がsvnベースのプラグインと同様にgitベースのプラグインでも動作するようになりました。
  • script/console--debuggerオプションがサポートされました。
  • Rails自体をビルドするためのCIサーバの設定方法は、Railsのソースコードに含まれています。
  • rake notes:custom ANNOTATION=MYFLAGでカスタムアノテーションをリストアップできます。
  • Rails.envStringInquirerでラップされ、Rails.env.development?が使えるようになりました。
  • Railsで非推奨の警告が表示されないようにし、gemの依存性を適切に扱うためには、rubygems 1.3.1以降が必須となりました。

11 非推奨化されたもの

今回のリリースで、一部の古いコードが非推奨化されました。

  • Rails::SecretKeyGeneratorActiveSupport::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をお使いください。

12 クレジット表記

リリースノート編集担当:Mike Gunderloy

フィードバックについて

Railsガイドは GitHub の yasslab/railsguides.jp で管理・公開されております。本ガイドを読んで気になる文章や間違ったコードを見かけたら、気軽に Pull Request を出して頂けると嬉しいです。Pull Request の送り方については GitHub の README をご参照ください。

原著における間違いを見つけたら『Rails のドキュメントに貢献する』を参考にしながらぜひ Rails コミュニティに貢献してみてください 🛠💨✨

本ガイドの品質向上に向けて、皆さまのご協力が得られれば嬉しいです。

Railsガイド運営チーム (@RailsGuidesJP)

支援・協賛

Railsガイドは下記の協賛企業から継続的な支援を受けています。支援・協賛にご興味あれば協賛プランからお問い合わせいただけると嬉しいです。

  1. Star
  2. このエントリーをはてなブックマークに追加