Rails アップグレードガイド

本章では、アプリケーションで使用されているRuby on Railsのバージョンを、新しいバージョンにアップグレードする際の手順について示します。アップグレードの手順は、Railsのバージョンごとに記載されています。

目次

  1. 一般的なアドバイス
  2. Rails 4.2からRails 5.0へのアップグレード
  3. Rails 4.1からRails 4.2へのアップグレード
  4. Rails 4.0からRails 4.1へのアップグレード
  5. Rails 3.2からRails 4.0へのアップグレード
  6. Rails 3.1からRails 3.2へのアップグレード
  7. Rails 3.0からRails 3.1へのアップグレード

1 一般的なアドバイス

言うまでもないことですが、既存のアプリケーションをアップグレードする際には、何のためにアップグレードするのかをはっきりさせておく必要があります。新しいバージョンのうちどの機能が必要になるのか、既存のコードのサポートがどのぐらい困難になるのか、アップグレードに必要な時間とスキルはどれほど必要かなど、いくつもの要素を調整しなければなりません。

1.1 テスティングのカバレッジ

アップグレード後にアプリケーションが正常に動作していることを確認する方法としては、良いテストカバレッジをアップグレード前に準備しておくのが最善です。アプリケーションを一気に検査する自動テストがないと、変更点をすべて手動で確認しなければならず膨大な時間がかかってしまいます。Railsのようなアプリケーションの場合、これはアプリケーションのあらゆる機能を一つ残らず確認しなければならないということです。アップグレードの実施は、テストカバレッジをきちんと準備してから行なうよう、お願いいたします。

1.2 アップグレード手順

Rails のバージョンを変更する場合、マイナーバージョンを1つずつゆっくりと変更して、非推奨機能の警告をすべて確認・利用するのが最善の方法であると言えます。言い換えると、アップグレードを急ぐあまりバージョンをスキップするべきではありません。Rails のバージョン番号は「メジャー番号.マイナー番号.パッチ番号」の形式を取ります。メジャーバージョンやマイナーバージョンが変更される場合、公開 API の変更によるエラーがアプリケーションで発生する可能性があります。パッチバージョンはバグ修正のみが含まれ、公開 API 変更は含まれません。

アップグレードは以下の手順で行います。

  1. テストを書き、テストがパスすることを確認する。
  2. 現時点のバージョンのパッチバージョンを最新のパッチに移行する。
  3. テストを修正し、非推奨の機能を修正する。
  4. 次のマイナーバージョンの最新パッチに移行する。

上の手順を繰り返して、最終的にRailsを目的のバージョンにアップグレードします。バージョンを移行するたびに、Gemfile 内の Rails バージョン番号を変更(これに伴い、他の gem のバージョン変更が必要になることもあります)し、bundle update を実行する必要があります。続いて、以下のアップデートタスクを実行して設定ファイルをアップデートし、テストを実行します。

リリース済みの Rails バージョンのリストはここで確認できます。

1.3 Rubyのバージョン

Railsは、そのバージョンがリリースされた時点で最新のバージョンのRubyに依存しています。

  • Rails 5 では Ruby 2.2.2 以降が必須です。
  • Rails 4ではRuby 2.0が推奨されます。Ruby 1.9.3以上が必須です。
  • Rails 3.2.xはRuby 1.8.7の最終ブランチです。
  • Rails 3以上では、Ruby 1.8.7以降が必須です。これより古いRubyのサポートは公式に停止しています。できるだけ早くアップグレードをお願いします。

Ruby 1.8.7 p248およびp249にはRailsをクラッシュさせるマーシャリングバグがあります。Ruby Enterprise Editionでは1.8.7-2010.02以降このバグは修正されています。Ruby 1.9系を使用する場合、Ruby 1.9.1はあからさまなセグメンテーション違反が発生するため使用できません。1.9.3をご使用ください。

1.4 アップデートタスク

Rails ではapp:updateというタスクが提供されています (Rails 4.2 以前では rails:update という名前でした)。Gemfileに記載されているRailsのバージョンを更新後、このタスクを実行することで、新しいバージョンでのファイル作成や既存ファイルの変更を対話形式で行うことができます。

$ rails app:update
   identical  config/boot.rb
       exist  config
    conflict  config/routes.rb
Overwrite /myapp/config/routes.rb? (enter "h" for help) [Ynaqdh]
       force  config/routes.rb
    conflict  config/application.rb
Overwrite /myapp/config/application.rb? (enter "h" for help) [Ynaqdh]
       force  config/application.rb
    conflict  config/environment.rb
...

予期しなかった変更が発生した場合は、必ず差分を十分にチェックしてください。

2 Rails 4.2からRails 5.0へのアップグレード

Rails 5.0 の変更点の詳細はリリースノートを参照してください。

2.1 Ruby 2.2.2以上が必須

Ruby on Rails 5.0 以降は、バージョン 2.2.2 以降の Ruby だけをサポートします。 Ruby のバージョンが 2.2.2 以降であることを確認してから手順を進めてください。

2.2 Active Record モデルは今後デフォルトで ApplicationRecord を継承する

Rails 4.2 の Active Record モデルは ActiveRecord::Base を継承していました。Rails 5.0 では、すべてのモデルが ApplicationRecord を継承するようになりました。

アプリのコントローラーがActionController::Baseに代わってApplicationControllerを継承するように、アプリのすべてのモデルがApplicationRecordをスーパークラスとして使うようになりました。この変更により、アプリ全体のモデルの動作を1か所で変更できるようになりました。

Rails 4.2 を Rails 5.0 にアップグレードする場合、app/models/ディレクトリにapplication_record.rbファイルを追加し、このファイルに以下の設定を追加する必要があります。

class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
end 

最後に、すべてのモデルが ApplicationRecord を継承するように変更および確認してください。

2.3 throw(:abort)でコールバックチェーンを停止する

Rails 4.2 では、Active RecordやActive Modelで'before'コールバックがfalseを返すと、すべてのコールバックチェーンが停止する仕様でした。この場合、以後'before'コールバックは実行されず、コールバック内にラップされているアクションも実行されません。

Rails 5.0 ではこの副作用が修正され、Active RecordやActive Modelのコールバックでfalseが返ってもコールバックチェーンが停止しなくなりました。その代わり、今後コールバックチェーンはthrow(:abort)で明示的に停止する必要があります。

Rails 4.2 を Rails 5.0 にアップグレードした場合、こうしたコールバックでfalseが返ったときに従来同様コールバックチェーンは停止しますが、この変更にともなう非推奨警告が表示されます。

この変更内容とその影響を十分理解しているのであれば、config/application.rbに以下の記述を追加して非推奨警告をオフにできます。

ActiveSupport.halt_callback_chains_on_return_false = false

Active Support のコールバックはこのオプションの影響を受けないことにご注意ください。Active Supportのチェーンはどのような値が返っても停止しません。

詳細については#17227を参照してください。

2.4 ActiveJob は今後デフォルトで ApplicationJob を継承する

Rails 4.2 のActive JobはActiveJob::Baseを継承しますが、Rails 5.0 ではデフォルトでApplicationJobを継承するよう変更されました。

Rails 4.2 を Rails 5.0 にアップグレードする場合、app/jobs/ディレクトリにapplication_job.rbファイルを追加し、このファイルに以下の設定を追加する必要があります。

class ApplicationJob < ActiveJob::Base
end 

これにより、すべてのjobクラスがActiveJob::Baseを継承するようになります。

詳細については#19034を参照してください。

2.5 Rails コントローラのテスト

2.5.1 いくつかのヘルパーメソッドを rails-controller-testing に抽出

assignsメソッドとassert_templateメソッドはrails-controller-testing gemに移転しました。これらのメソッドを引き続きコントローラのテストで使いたい場合は、Gemfileにgem 'rails-controller-testing'を追加してください。

テストでRspecを使っている場合は、このgemのドキュメントで必須となっている追加の設定方法もご確認ください。

2.5.2 ファイルアップロード時の新しい振る舞い

ファイルアップロードのテストでActionDispatch::Http::UploadedFileクラスを使用している場合、Rack::Test::UploadedFileクラスに変更する必要があります。

詳細については#26404を参照してください。

2.6 production 環境での起動後は自動読み込みが無効になる

今後Railsがproduction環境で起動されると、自動読み込みがデフォルトで無効になります。

アプリケーションの一括読み込み(eager loading)は起動プロセスに含まれています。このため、トップレベルの定数についてはファイルをrequireしなくても問題なく利用でき、従来と同様に自動読み込みされます。

トップレベルより下で、実行時にのみ有効にする定数(通常のメソッド本体など)を定義した場合も、起動時に一括読み込みされるので問題なく利用できます。

ほとんどのアプリケーションでは、この変更に関して特別な対応は不要です。めったにないと思われますが、productionモードで動作するアプリケーションで自動読み込みが必要な場合は、Rails.application.config.enable_dependency_loadingをtrueに設定してください。

2.7 XML シリアライズ

RailsのActiveModel::Serializers::Xmlactivemodel-serializers-xml gemに移転しました。アプリケーションで今後もXMLシリアライズを使うには、Gemfileに「gem 'activemodel-serializers-xml'」を追加してください。

2.8 古い mysql データベース アダプタのサポートを終了

Rails 5で古いmysqlデータベース アダプタのサポートが終了しました。原則としてmysql2をお使いください。今後古いアダプタのメンテナンス担当者が決まった場合、アダプタは別のgemに切り出されます。

2.9 デバッガのサポートを終了

Rails 5が必要とするRuby 2.2では、debuggerはサポートされていません。代わりに、今後はbyebugをお使いください。

2.10 タスクやテストの実行には bin/rails を使うこと

Rails 5 では、rakeに代わってbin/railsでタスクやテストを実行できるようになりました。原則として、多くのタスクやテストはrakeでも引き続き実行できますが、一部のタスクやテストは完全にbin/railsに移行しました。

今後テストの実行には「bin/rails test」をお使いください。

rake dev:cache」は「rails dev:cache」に変更されました。

bin/rails」を実行すると、利用可能なコマンドリストを表示できます。

2.11 ActionController::Parameters は今後 HashWithIndifferentAccess を継承しない

アプリケーションで params を呼び出すと、今後はハッシュではなくオブジェクトが返ります。現在使っているパラメーターがRailsで既に利用できている場合、変更は不要です。permitted?の状態にかかわらずハッシュを読み取れることが前提のメソッド(sliceメソッドなど)にコードが依存している場合、まずアプリケーションをアップグレードしてpermitを指定し、続いてハッシュに変換する必要があります。

params.permit([:proceed_to, :return_to]).to_h

2.12 protect_from_forgery は今後デフォルトで prepend: false に設定される

protect_from_forgery は今後デフォルトで prepend: false に設定されます。これにより、protect_from_forgeryはアプリケーションで呼び出される時点でコールバックチェーンに挿入されます。protect_from_forgeryを常に最初に実行したい場合は、アプリケーションの設定でprotect_from_forgery prepend: trueを指定する必要があります。

2.13 デフォルトのテンプレート ハンドラは今後 RAW になる

拡張子がテンプレートハンドラになっていないファイルは、今後rawハンドラで出力されるようになります。従来のRailsでは、このような場合にはERBテンプレートハンドラで出力されました。

ファイルをrawハンドラで出力したくない場合は、ファイルに明示的に拡張子を与え、適切なテンプレート ハンドラで処理されるようにしてください。

2.14 テンプレート依存関係の指定でワイルドカードマッチングが追加された

テンプレート依存関係をワイルドカードマッチングで指定できるようになりました。以下のテンプレートを例に説明します。

<% # Template Dependency: recordings/threads/events/subscribers_changed %>
<% # Template Dependency: recordings/threads/events/completed %>
<% # Template Dependency: recordings/threads/events/uncompleted %>

上のようなテンプレートは、以下のようにワイルドカードを使えば1行で設定できます。

<% # Template Dependency: recordings/threads/events/* %>

2.15 protected_attributes gem のサポートを終了

protected_attributes gemのサポートは Rails 5 で終了しました。

2.16 activerecord-deprecated_finders gem のサポートを終了

activerecord-deprecated_finders gemのサポートは Rails 5 で終了しました。

2.17 ActiveSupport::TestCase でのテストは今後デフォルトでランダムに実行される

アプリケーションのテストのデフォルトの実行順序は、従来の:sortedから:randomに変更されました。:sortedに戻すには以下のオプションを指定します。

# config/environments/test.rb
Rails.application.configure do
  config.active_support.test_order = :sorted
end 

2.18 ActionController::LiveConcern に変更された

コントローラにincludeされている別のモジュールにActionController::Liveがincludeされている場合、ActiveSupport::Concernをextendするコードの追加も必要です。または、StreamingSupportがincludeされてから、self.includedフックを使ってActionController::Liveをコントローラに直接includeすることもできます。

理由: アプリケーションで独自のストリーミングモジュールを使用している場合、以下のコードはproductionモードで正常に動作しなくなる可能性があります。

# Warden/Devise で認証するストリーミングコントローラでの回避方法を示すコード
# https://github.com/plataformatec/devise/issues/2332 を参照
# 上のissueではルーター内での認証で解決する方法もアドバイスされている
class StreamingSupport
  include ActionController::Live # Rails 5 の production モードではこの行は動作しない
  # extend ActiveSupport::Concern # この行をコメント解除することで上の行が動作するようになる

  def process(name)
    super(name)
  rescue ArgumentError => e
    if e.message == 'uncaught throw :warden'
      throw :warden
    else
      raise e
    end
  end
end

2.19 フレームワークの新しいデフォルト設定

2.19.1 Active Recordのbelongs_toはデフォルトオプションで必須

関連付けが存在しない場合、belongs_toでバリデーションエラーが発生するようになりました。

なお、この機能は関連付けごとにoptional: trueを指定してオフにできます。

新しいアプリケーションでは、このデフォルト設定が自動で有効になります。この設定を既存のアプリケーションに追加するには、イニシャライザでこの機能をオンにする必要があります

config.active_record.belongs_to_required_by_default = true
2.19.2 フォームごとのCSRFトークン

Rails 5 では、JavaScriptで作成されたフォームによるコードインジェクション攻撃に対応するため、フォーム単位でのCSRFトークンをサポートします。このオプションがオンの場合、アクションやメソッドで指定したCSRFトークンがアプリケーションのフォームごとに個別に生成されるようになります。

config.action_controller.per_form_csrf_tokens = true
2.19.3 OriginチェックによるCSRF対策

アプリケーションで、CSRF防御の一環としてHTTP Originヘッダによるサイトの出自チェックを設定できるようになりました。以下の設定をtrueにすることで有効になります。

config.action_controller.forgery_protection_origin_check = true
2.19.4 Action Mailerのキュー名がカスタマイズ可能に

デフォルトのメイラー キュー名はmailersです。新しい設定オプションを使うと、キュー名をグローバルに変更できます。以下の方法で設定します。

config.action_mailer.deliver_later_queue_name = :new_queue_name
2.19.5 Action Mailer のビューでフラグメントキャッシュをサポート

設定ファイルの config.action_mailer.perform_caching で、Action Mailerのビューでキャッシュをサポートするかどうかを指定できます。

config.action_mailer.perform_caching = true
2.19.6 db:structure:dumpの出力形式のカスタマイズ

schema_search_pathや、その他のPostgreSQLエクステンションを使っている場合、スキーマのダンプ方法を指定できます。以下のように:allを指定するとすべてのダンプが生成され、:schema_search_pathを指定するとスキーマ検索パスからダンプが生成されます。

config.active_record.dump_schemas = :all
2.19.7 サブドメインでのHSTSを有効にするSSLオプション

サブドメインで HSTS(HTTP Strict Transport Security)を有効にするには、以下の設定を使います。

config.ssl_options = { hsts: { subdomains: true } }
2.19.8 レシーバのタイムゾーンを保存する

Ruby 2.4を利用している場合、to_timeの呼び出しでレシーバのタイムゾーンを保存できます。

ActiveSupport.to_time_preserves_timezone = false

3 Rails 4.1からRails 4.2へのアップグレード

3.1 Web Console gem

最初に、Gemfileのdevelopmentグループにgem 'web-console', '~> 2.0'を追加し、bundle installを実行してください (このgemはRailsを過去のバージョンからアップグレードした場合には含まれないので、手動で追加する必要があります)。gemのインストール完了後、<%= console %>などのコンソールヘルパーへの参照をビューに追加するだけで、どのビューでもコンソールを利用できるようになります。このコンソールは、development環境のビューで表示されるすべてのエラーページにも表示されます。

3.2 Responders gem

respond_withおよびクラスレベルのrespond_toメソッドは、responders gemに移転しました。これらのメソッドを使用したい場合は、Gemfileにgem 'responders', '~> 2.0'と記述するだけで利用できます。今後、respond_with呼び出し、およびクラスレベルのrespond_to呼び出しは、responders gemなしでは動作しません。

# app/controllers/users_controller.rb

class UsersController < ApplicationController
  respond_to :html, :json

  def show
    @user = User.find(params[:id])
    respond_with @user
  end
end

インスタンスレベルのrespond_toは今回のアップグレードの影響を受けませんので、gemを追加する必要はありません。

# app/controllers/users_controller.rb

class UsersController < ApplicationController
  def show
    @user = User.find(params[:id])
    respond_to do |format|
      format.html
      format.json { render json: @user }
    end
  end
end

詳細については#16526を参照してください。

3.3 トランザクションコールバックのエラー処理

現在のActive Recordでは、after_rollbackafter_commitコールバックでの例外を抑制しており、例外時にはログ出力のみが行われます。次のバージョンからは、これらのエラーは抑制されなくなりますのでご注意ください。今後は他のActive Recordコールバックと同様のエラー処理を行います。

after_rollbackコールバックやafter_commitコールバックを定義すると、この変更にともなう非推奨警告が表示されるようになりました。この変更内容を十分理解し、受け入れる準備ができているのであれば、config/application.rbに以下の記述を行なうことで非推奨警告が表示されないようにすることができます。

config.active_record.raise_in_transactional_callbacks = true

詳細については、#14488および#16537を参照してください。

3.4 テストケースの実行順序

Rails 5.0のテストケースは、デフォルトでランダムに実行されるようになる予定です。この変更に備えて、テスト実行順を明示的に指定するactive_support.test_orderという新しい設定オプションがRails 4.2に導入されました。このオプションを使用すると、たとえばテスト実行順を現行の仕様のままにしておきたい場合は:sortedを指定したり、ランダム実行を今のうちに導入したい場合は:randomを指定したりすることができます。

このオプションに値が指定されていないと、非推奨警告が表示されます。非推奨警告が表示されないようにするには、test環境に以下の記述を追加します。

# config/environments/test.rb
Rails.application.configure do
  config.active_support.test_order = :sorted # `:random`にしてもよい
end

3.5 シリアル化属性

serialize :metadata, JSONなどのカスタムコーダーを使用している場合に、シリアル化属性 (serialized attribute) にnilを割り当てると、コーダー内でnil値を渡すのではなく、データベースにNULLとして保存されるようになりました (JSONコーダーを使用している場合の"null"など)。

3.6 Productionログのレベル

Rails 5のproduction環境では、デフォルトのログレベルが:infoから:debugに変更される予定です。現在のログレベルを変更したくない場合はproduction.rbに以下の行を追加してください。

# `:info`を指定すると現在のデフォルト設定が使用され、
# `:debug`を指定すると今後のデフォルト設定が使用される
config.log_level = :info

3.7 Railsテンプレートのafter_bundle

Railsテンプレートを使用し、かつすべてのファイルを (Gitなどで) バージョン管理している場合、生成されたbinstubをバージョン管理システムに追加できません。これは、binstubの生成がBundlerの実行前に行われるためです。

# template.rb
generate(:scaffold, "person name:string")
route "root to: 'people#index'"
$ rake db:migrate

git :init
git add: "."
git commit: %Q{ -m 'Initial commit' }

この問題を回避するために、git呼び出しをafter_bundleブロック内に置くことができるようになりました。こうすることで、binstubの生成が終わってからBundlerが実行されます。

# template.rb
generate(:scaffold, "person name:string")
route "root to: 'people#index'"
rake("db:migrate")

after_bundle do
  git :init
  git add: "."
  git commit: %Q{ -m 'Initial commit' }
end

3.8 RailsのHTMLサニタイザ

アプリケーションでHTMLの断片をサニタイズする方法に新しい選択肢が1つ増えました。従来の伝統的なHTMLスキャンによるサニタイズは公式に非推奨化されました。現在推奨される方法はRails HTMLサニタイザです。

これにより、sanitizesanitize_cssstrip_tags、およびstrip_linksメソッドは新しい実装に基いて動作するようになります。

新しいサニタイザは、内部でLoofahを使用しています。そしてLoofahはNokogiriを使用しています。Nokogiriで使用されているXMLパーサーはCとJavaの両方で記述されているので、使用しているRubyのバージョンにかかわらずサニタイズが高速化されるようになりました。

新しいRailsではsanitizeメソッドが更新され、Loofah::Scrubberを使用して強力なスクラブを行なうことができます。スクラブの使用例はここを参照

PermitScrubberおよびTargetScrubberという2つのスクラバーが新たに追加されました。詳細については、gemのReadmeを参照してください。

PermitScrubberおよびTargetScrubberのドキュメントには、どの要素をどのタイミングで除去すべきかを完全に制御する方法が記載されています。

従来のままのサニタイザの実装が必要な場合は、アプリケーションのGemfileにrails-deprecated_sanitizerを追加してください。

gem 'rails-deprecated_sanitizer'

3.9 RailsのDOMのテスト

assert_tagなどを含むTagAssertionsモジュール非推奨になりました。今後推奨されるのは、ActionViewからrails-dom-testing gemに移行したSelectorAssertionsモジュールのassert_selectメソッドです。

3.10 マスク済み真正性トークン

SSL攻撃を緩和するために、form_authenticity_tokenがマスクされるようになりました。これにより、このトークンはリクエストごとに変更されます。トークンの検証はマスク解除 (unmasking)とそれに続く復号化 (decrypting) によって行われます。この変更が行われたことにより、railsアプリケーション以外のフォームから送信される、静的なセッションCSRFトークンに依存するリクエストを検証する際には、このマスク済み真正性トークンのことを常に考慮する必要がありますのでご注意ください。

3.11 Action Mailer

従来は、メイラークラスでメイラーメソッドを呼び出すと、該当するインスタンスメソッドが直接実行されました。Active Jobと#deliver_laterメソッドの導入に伴い、この動作が変更されました。Rails 4.2では、これらのインスタンスメソッド呼び出しはdeliver_nowまたはdeliver_laterが呼び出されるまで実行延期されます。以下に例を示します。

class Notifier < ActionMailer::Base
  def notify(user, ...)
    puts "Called"
    mail(to: user.email, ...)
  end
end

mail = Notifier.notify(user, ...) # Notifier#notifyはこの時点では呼び出されない
mail = mail.deliver_now           # "Called"を出力する

この変更によって実行結果が大きく異なるアプリケーションはそれほどないと思われます。ただし、メイラー以外のメソッドを同期的に実行したい場合、かつ従来の同期的プロキシ動作に依存している場合は、これらのメソッドをメイラークラスにクラスメソッドとして直接定義する必要があります。

class Notifier < ActionMailer::Base
  def self.broadcast_notifications(users, ...)
    users.each { |user| Notifier.notify(user, ...) }
  end
end

3.12 外部キーのサポート

移行DSLが拡張され、外部キー定義をサポートするようになりました。Foreigner gemを使っていた場合は、この機会に削除するとよいでしょう。Railsの外部キーサポートは、Foreignerの全機能ではなく、一部のみである点にご注意ください。このため、Foreignerの定義を必ずしもRailsの移行DSLに置き換えられないことがあります。

移行手順は次のとおりです。

  1. Gemfileからgem "foreigner"を削除します。
  2. bundle installを実行します。
  3. bin/rake db:schema:dumpを実行します。
  4. 外部キー定義と必要なオプションがdb/schema.rbにすべて含まれていることを確認します。

4 Rails 4.0からRails 4.1へのアップグレード

4.1 リモート <script> タグにCSRF保護を実施

これを行わないと、「なぜかテストがとおらない...orz」「<script>ウィジェットがおかしい!」などという結果になりかねません。

JavaScriptレスポンスを伴うGETリクエストもクロスサイトリクエストフォージェリ (CSRF) 保護の対象となりました。これは、サイトの<script>タグのJavaScriptが第三者のサイトから参照されて重要なデータが奪取されないよう保護するためのものです。

つまり、以下を使用する機能テストと結合テストは

get :index, format: :js

CSRF保護をトリガーするようになります。以下のように書き換え、

xhr :get, :index, format: :js

XmlHttpRequestを明示的にテストしてください。

自サイトの<script>はクロス参照の出発点として扱われるため、同様にブロックされます。JavaScriptを本当に<script>タグから読み込む場合は、そのアクションでCSRF保護を明示的にスキップしてください。

4.2 Spring

アプリケーションのプリローダーとしてSpringを使用する場合は、以下を行う必要があります。

  1. gem 'spring', group: :developmentGemfileに追加する
  2. bundle installを実行してSpringをインストールする
  3. bundle exec spring binstub --allを実行してbinstubをSpring化する

ユーザーが定義したRakeタスクはデフォルトでdevelopment環境で動作するようになります。これらのRakeタスクを他の環境でも実行したい場合はSpring READMEを参考にしてください。

4.3 config/secrets.yml

新しいsecrets.ymlに秘密鍵を保存したい場合は以下の手順を実行します。

  1. secrets.ymlファイルをconfigフォルダ内に作成し、以下の内容を追加します。

    development:
      secret_key_base:
    
    test:
      secret_key_base:
    
    production:
      secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
    
  2. secret_token.rbイニシャライザに記載されている既存の secret_key_baseの秘密キーを取り出してSECRET_KEY_BASE環境変数に設定し、Railsアプリケーションをproductionモードで実行するすべてのユーザーが秘密キーの恩恵を受けられるようにします。あるいは、既存のsecret_key_basesecret_token.rbイニシャライザからsecrets.ymlのproductionセクションにコピーし、'<%= ENV["SECRET_KEY_BASE"] %>'を置き換えることもできます。

  3. secret_token.rbイニシャライザを削除します

  4. rake secretを実行し、developmentセクションtestセクションに新しい鍵を生成します。

  5. サーバーを再起動します。

4.4 テストヘルパーの変更

テストヘルパーに含まれているActiveRecord::Migration.check_pending!呼び出しは削除できます。このチェックはrequire 'rails/test_help'の際に自動的に行われるようになりました。この呼び出しを削除しなくても悪影響が生じることはありません。

4.5 Cookiesシリアライザ

Rails 4.1より前に作成されたアプリケーションでは、Marshalを使用してcookie値を署名済みまたは暗号化したcookies jarにシリアライズしていました。アプリケーションで新しいJSONベースのフォーマットを使用したい場合、以下のような内容を持つイニシャライザファイルを追加できます。

Rails.application.config.action_dispatch.cookies_serializer = :hybrid

これにより、Marshalでシリアライズされた既存のcookiesを、新しいJSONベースのフォーマットに透過的に移行できます。

:jsonまたは:hybridシリアライザを使用する場合、一部のRubyオブジェクトがJSONとしてシリアライズされない可能性があることにご注意ください。たとえば、DateオブジェクトやTimeオブジェクトはstringsとしてシリアライズされ、Hashのキーはstringに変換されます。

class CookiesController < ApplicationController
  def set_cookie
    cookies.encrypted[:expiration_date] = Date.tomorrow # => Thu, 20 Mar 2014
    redirect_to action: 'read_cookie'
  end

  def read_cookie
    cookies.encrypted[:expiration_date] # => "2014-03-20"
  end
end

cookieには文字列や数字などの単純なデータだけを保存することをお勧めします。cookiesに複雑なオブジェクトを保存しなければならない場合は、後続のリクエストでcookiesから値を読み出す場合の変換については自分で面倒を見る必要があります。

cookieセッションストアを使用する場合、sessionflashハッシュについてもこのことは該当します。

4.6 Flash構造の変更

Flashメッセージのキーが文字列に正規化 されました。シンボルまたは文字列のどちらでもアクセスできます。Flashのキーを取り出すと常に文字列になります。

flash["string"] = "a string"
flash[:symbol] = "a symbol"

# Rails < 4.1
flash.keys # => ["string", :symbol]

# Rails >= 4.1
flash.keys # => ["string", "symbol"]

Flashメッセージのキーは文字列と比較してください。

4.7 JSONの扱いの変更点

Rails 4.1ではJSONの扱いが大きく変更された点が4つあります。

4.7.1 MultiJSONの廃止

MultiJSONはその役目を終えて end-of-life Railsから削除されました。

アプリケーションがMultiJSONに直接依存している場合、以下のような対応方法があります。

  1. 'multi_json'をGemfileに追加する。ただしこのGemは将来使えなくなるかもしれません。

  2. obj.to_jsonJSON.parse(str)を使用してMultiJSONから乗り換える。

MultiJson.dumpMultiJson.loadをそれぞれJSON.dumpJSON.loadに単純に置き換えては「いけません」。これらのJSON gem APIは任意のRubyオブジェクトをシリアライズおよびデシリアライズするためのものであり、一般に安全ではありません

4.7.2 JSON gemの互換性

これまでのRailsでは、JSON gemとの互換性に何らかの問題が生じていました。Railsアプリケーション内のJSON.generateJSON.dumpではときたまエラーが生じることがありました。

Rails 4.1では、Rails自身のエンコーダをJSON gemから切り離すことでこれらの問題が修正されました。JSON gem APIは今後正常に動作しますが、その代わりJSON gem APIからRails特有の機能にアクセスすることはできなくなります。以下に例を示します。

class FooBar
  def as_json(options = nil)
    { foo: 'bar' }
  end
end

>> FooBar.new.to_json # => "{\"foo\":\"bar\"}"
>> JSON.generate(FooBar.new, quirks_mode: true) # => "\"#<FooBar:0x007fa80a481610>\""
4.7.3 新しいJSONエンコーダ

Rails 4.1のJSONエンコーダは、JSON gemを使用するように書き直されました。この変更によるアプリケーションへの影響はほとんどありません。ただし、エンコーダが書き直された際に以下の機能がエンコーダから削除されました。

  1. データ構造の循環検出
  2. encode_jsonフックのサポート
  3. BigDecimalオブジェクトを文字ではなく数字としてエンコードするオプション

アプリケーションがこれらの機能に依存している場合は、activesupport-json_encoder gemをGemfileに追加することで以前の状態に戻すことができます。

4.7.4 TimeオブジェクトのJSON形式表現

日時に関連するコンポーネント(TimeDateTimeActiveSupport::TimeWithZone)を持つオブジェクトに対して#as_jsonを実行すると、デフォルトでミリ秒単位の精度で値が返されるようになりました。ミリ秒より精度の低い従来方式にしておきたい場合は、イニシャライザに以下を設定してください。

ActiveSupport::JSON::Encoding.time_precision = 0

4.8 インラインコールバックブロックでreturnの使用法

以前のRailsでは、インラインコールバックブロックで以下のようにreturnを使用することが許容されていました。

class ReadOnlyModel < ActiveRecord::Base
  before_save { return false } # 良くない
end

この動作は決して意図されたものではありません。ActiveSupport::Callbacksが書き直され、上のような動作はRails 4.1では許容されなくなりました。インラインコールバックブロックでreturn文を書くと、コールバック実行時にLocalJumpErrorが発生するようになりました。

インラインコールバックブロックでreturnを使用している場合、以下のようにリファクタリングすることで、返された値として評価されるようになります。

class ReadOnlyModel < ActiveRecord::Base
  before_save { false } # 良い
end

returnを使用したいのであれば、明示的にメソッドを定義することが推奨されます。

class ReadOnlyModel < ActiveRecord::Base
  before_save :before_save_callback # 良い

  private
    def before_save_callback
      return false
    end
end

この変更は、Railsでコールバックを使用している多くの箇所に適用されます。これにはActive RecordとActive ModelのコールバックやAction Controllerのフィルタ(before_action など)も含まれます。

詳細についてはこのpull requestを参照してください。

4.9 Active Recordフィクスチャで定義されたメソッド

Rails 4.1では、各フィクスチャのERBは独立したコンテキストで評価されます。このため、あるフィクスチャで定義されたヘルパーメソッドは他のフィクスチャでは利用できません。

ヘルパーメソッドを複数のフィクスチャで使用するには、4.1で新しく導入されたActiveRecord::FixtureSet.context_class (test_helper.rb) に含まれるモジュールで定義する必要があります。

module FixtureFileHelpers
  def file_sha(path)
    Digest::SHA2.hexdigest(File.read(Rails.root.join('test/fixtures', path)))
  end
end 
ActiveRecord::FixtureSet.context_class.include FixtureFileHelpers

4.10 I18nオプションでavailable_localesリストの使用が強制される

Rails 4.1からI18nオプションenforce_available_localesがデフォルトでtrueになりました。この設定にすると、I18nに渡されるすべてのロケールは、available_localesリストで宣言されていなければ使用できません。

この機能をオフにしてI18nですべての種類のロケールオプションを使用できるようにするには、以下のように変更します。

config.i18n.enforce_available_locales = false

available_localesの強制はセキュリティのために行われていることにご注意ください。つまり、アプリケーションが把握していないロケールを持つユーザー入力が、ロケール情報として使用されることのないようにするためのものです。従って、やむを得ない理由がない限りこのオプションはfalseにしないでください。

4.11 リレーションに対する破壊的メソッド呼び出し

Relationには#map!#delete_ifなどの破壊的メソッド (mutator method) が含まれなくなりました。これらのメソッドを使用したい場合は#to_aを呼び出してArrayに変更してからにしてください。

この変更は、Relationに対して破壊的メソッドを直接呼び出すことによる奇妙なバグや混乱を防止するために行われました。

# 以前の破壊的な呼び出し方法
Author.where(name: 'Hank Moody').compact!

# 今後の破壊的な呼び出し方法
authors = Author.where(name: 'Hank Moody').to_a
authors.compact!

4.12 デフォルトスコープの変更

デフォルトのスコープは、条件を連鎖した場合にオーバーライドされなくなりました。

以前のバージョンでは、モデルでdefault_scopeを定義すると、同じフィールドで連鎖した条件によってオーバーライドされました。現在は、他のスコープと同様、マージされるようになりました。

変更前:

class User < ActiveRecord::Base
  default_scope { where state: 'pending' }
  scope :active, -> { where state: 'active' }
  scope :inactive, -> { where state: 'inactive' }
end

User.all
# SELECT "users".* FROM "users" WHERE "users"."state" = 'pending'

User.active
# SELECT "users".* FROM "users" WHERE "users"."state" = 'active'

User.where(state: 'inactive')
# SELECT "users".* FROM "users" WHERE "users"."state" = 'inactive'

変更後:

class User < ActiveRecord::Base
  default_scope { where state: 'pending' }
  scope :active, -> { where state: 'active' }
  scope :inactive, -> { where state: 'inactive' }
end

User.all
# SELECT "users".* FROM "users" WHERE "users"."state" = 'pending'

User.active
# SELECT "users".* FROM "users" WHERE "users"."state" = 'pending' AND "users"."state" = 'active'

User.where(state: 'inactive')
# SELECT "users".* FROM "users" WHERE "users"."state" = 'pending' AND "users"."state" = 'inactive'

以前と同じ動作に戻したい場合は、unscopedunscoperewhere、またはexceptを使用してdefault_scopeの条件を明示的に除外する必要があります。

class User < ActiveRecord::Base
  default_scope { where state: 'pending' }
  scope :active, -> { unscope(where: :state).where(state: 'active') }
  scope :inactive, -> { rewhere state: 'inactive' }
end

User.all
# SELECT "users".* FROM "users" WHERE "users"."state" = 'pending'

User.active
# SELECT "users".* FROM "users" WHERE "users"."state" = 'active'

User.inactive
# SELECT "users".* FROM "users" WHERE "users"."state" = 'inactive'

4.13 文字列からのコンテンツ描出

Rails 4.1のrender:plain:html:bodyオプションが導入されました。以下のようにコンテンツタイプを指定できるため、文字列ベースのコンテンツ表示にはこれらのオプションの使用が推奨されます。

  • render :plainを実行するとcontent typeはtext/plainに設定される
  • render :htmlを実行するとcontent typeはtext/htmlに設定される
  • render :bodyを実行した場合、content typeヘッダーは「設定されない」

セキュリティ上の観点から、レスポンスのbodyにマークアップを含めない場合にはrender :plainを使用すべきです。これによって多くのブラウザが安全でないコンテンツをエスケープできるからです。

今後のバージョンでは、render :textは非推奨にされる予定です。今のうちに、正しい:plain:html:bodyオプションに切り替えてください。render :textを使用するとtext/htmlで送信されるため、セキュリティ上のリスクが生じる可能性があります。

4.14 PostgreSQLのデータ型'json'と'hstore'について

Rails 4.1では、PostgreSQLのjsonカラムとhstoreカラムを、文字列をキーとするRubyのHashに対応付けるようになりました。なお、以前のバージョンではHashWithIndifferentAccessが使用されていました。この変更は、Rails 4.1以降ではシンボルを使用してこれらのデータ型にアクセスできなくなるということを意味します。store_accessorsメソッドはjsonカラムやhstoreカラムに依存しているので、同様にシンボルでのアクセスが行えなくなります。今後は常に文字列をキーにするようにしてください。

4.15 ActiveSupport::Callbacksでは明示的にブロックを使用すること

Rails 4.1からはActiveSupport::Callbacks.set_callbackの呼び出しの際に明示的にブロックを渡すことが期待されます。これは、ActiveSupport::CallbacksがRails 4.1リリースにあたって大幅に書き換えられたことによるものです。

# Rails 4.0の場合
set_callback :save, :around, ->(r, &block) { stuff; result = block.call; stuff }

# Rails 4.1の場合
set_callback :save, :around, ->(r, block) { stuff; result = block.call; stuff }

5 Rails 3.2からRails 4.0へのアップグレード

Railsアプリケーションのバージョンが3.2より前の場合、まず3.2へのアップグレードを完了してからRails 4.0へのアップグレードを開始してください。

以下の変更は、アプリケーションをRails 4.0にアップグレードするためのものです。

5.1 HTTP PATCH

Rails 4では、config/routes.rbでRESTfulなリソースが宣言されたときに、更新用の主要なHTTP verbとしてPATCHが使用されるようになりました。updateアクションは従来通り使用でき、PUTリクエストは今後もupdateアクションにルーティングされます。標準的なRESTfulのみを使用しているのであれば、これに関する変更は不要です。

resources :users
<%= form_for @user do |f| %>
class UsersController < ApplicationController
  def update
    # 変更不要:PATCHが望ましいがPUTも使用できる
  end
end

ただし、form_forを使用してリソースを更新しており、PUT HTTPメソッドを使用するカスタムルーティングと連動しているのであれば、変更が必要です。

resources :users, do
  put :update_name, on: :member
end
<%= form_for [ :update_name, @user ] do |f| %>
class UsersController < ApplicationController
  def update_name
    # 変更が必要: form_forは、存在しないPATCHルートを探そうとする
  end
end

このアクションがパブリックなAPIで使用されておらず、HTTPメソッドを自由に変更できるのであれば、ルーティングを更新してpatchputの代りに使用できます。

Rails 4でPUTリクエストを/users/:idに送信すると、従来と同様updateにルーティングされます。このため、実際のPUTリクエストを受け取るAPIは今後も利用できます。この場合、PATCHリクエストも/users/:id経由でupdateアクションにルーティングされます。

resources :users do
  patch :update_name, on: :member
end

このアクションがパブリックなAPIで使用されており、HTTPメソッドを自由に変更できないのであれば、フォームを更新してPUTを代りに使用できます。

<%= form_for [ :update_name, @user ], method: :put do |f| %>

PATCHおよびこの変更が行われた理由についてはRailsブログの この記事 を参照してください。

5.1.1 メディアタイプに関するメモ

PATCH verbに関する追加情報 PATCHでは異なるメディアタイプを使用する必要があるJSON Patch などが該当します。RailsはJSON Patchをネイティブではサポートしませんが、サポートは簡単に追加できます。

# コントローラに以下を書く
def update
  respond_to do |format|
    format.json do
      # 部分的な変更を行なう
      @article.update params[:article]
    end

    format.json_patch do
      # 何か気の利いた変更を行なう
    end
  end
end

# config/initializers/json_patch.rb に以下を書く
Mime::Type.register 'application/json-patch+json', :json_patch

JSON Patchは最近RFC化されたばかりなのでRubyライブラリはそれほどありません。Aaron Pattersonの hana gemが代表的ですが、最新の仕様変更をすべてサポートしているわけではありません。

5.2 Gemfile

Rails 4.0ではassetsグループがGemfileから削除されました。アップグレード時にはこの記述をGemfileから削除する必要があります。アプリケーションのconfig/application.rbファイルも以下のように更新する必要があります。

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

5.3 vendor/plugins

Rails 4.0 では vendor/plugins 読み込みのサポートは完全に終了しました。使用するプラグインはすべてgemに展開してGemfileに追加しなければなりません。 理由があってプラグインをgemにしないのであれば、プラグインをlib/my_plugin/*に移動し、適切な初期化の記述をconfig/initializers/my_plugin.rbに書いてください。

5.4 Active Record

  • 関連付けに関する若干の不整合 のため、Rails 4.0ではActive Recordからidentity mapが削除されました。この機能をアプリケーションで手動で有効にしたい場合は、今や無効になったconfig.active_record.identity_mapを削除する必要があるでしょう。

コレクション関連付けのdeleteメソッドは、integerString引数をレコードの他にレコードIDとしても受け付けるようになりました。これによりdestroyメソッドの動作にかなり近くなりました。以前はこのような引数を使用するとActiveRecord::AssociationTypeMismatch例外が発生しました。Rails 4.0からは、deleteメソッドを使用すると、与えられたIDにマッチするレコードを自動的に探すようになりました。

  • Rails 4.0では、カラムやテーブルの名前を変更すると、関連するインデックスも自動的にリネームされるようになりました。インデックス名を変更するためだけのマイグレーションは今後不要になりました。

  • Rails 4.0のserialized_attributesメソッドとattr_readonlyメソッドは、クラスメソッドとしてのみ使用するように変更されました。これらのメソッドをインスタンスメソッドとして使用することは非推奨となったため、行わないでください。たとえばself.serialized_attributesself.class.serialized_attributesのようにクラスメソッドとして使用してください。

  • デフォルトのコーダーを使用する場合、シリアル化属性にnilを渡すと、YAML全体にわたって (nil値を渡す代わりに) NULLとしてデータベースに保存されます ("--- \n...\n")。

  • Rails 4.0ではStrong Parametersの導入に伴い、attr_accessibleattr_protectedが廃止されました。これらを引き続き使用したい場合は、Protected Attributes gem を導入することでスムーズにアップグレードすることができます。

  • Protected Attributesを使用していないのであれば、whitelist_attributesmass_assignment_sanitizerオプションなど、このgemに関連するすべてのオプションを削除できます。

  • Rails 4.0のスコープでは、Procやlambdaなどの呼び出し可能なオブジェクトの使用が必須となりました。

  scope :active, where(active: true)

  # 上のコードは以下のように変更する必要がある
  scope :active, -> { where active: true }
  • ActiveRecord::FixtureSetの導入に伴い、Rails 4.0ではActiveRecord::Fixturesが非推奨となりました。

  • ActiveSupport::TestCaseの導入に伴い、Rails 4.0ではActiveRecord::TestCaseが非推奨となりました。

  • Rails 4.0では、ハッシュを使用する旧来のfinder APIが非推奨となりました。これまでfinderオプションを受け付けていたメソッドは、これらのオプションを今後受け付けなくなります。たとえば、Book.find(:all, conditions: { name: '1984' })は非推奨です。今後はBook.where(name: '1984')をご使用ください。

  • 動的なメソッドは、find_by_...find_by_...!を除いて非推奨になりました。以下のように変更してください。

    • find_all_by_... に代えて where(...) を使用
    • find_last_by_... に代えて where(...).last を使用
    • scoped_by_... に代えて where(...) を使用`
    • find_or_initialize_by_... に代えてfind_or_initialize_by(...)を使用`
    • find_or_create_by_... に代えてfind_or_create_by(...)を使用`
  • 旧来のfinderが配列を返していたのに対し、where(...)はリレーションを返します。Arrayが必要な場合は, where(...).to_aを使用してください。

  • これらの同等なメソッドが実行するSQLは、従来の実装と同じではありません。

  • 旧来のfinderを再度有効にしたい場合は、activerecord-deprecated_finders gem を使用できます。

  • Rails 4.0 では、has_and_belongs_to_manyリレーションで2番目のテーブル名の共通プレフィックスを除去する際に、デフォルトでjoin tableを使うよう変更されました。共通プレフィックスがあるモデル同士のhas_and_belongs_to_manyリレーションでは、必ずjoin_tableオプションを指定する必要があります。以下に例を示します。

CatalogCategory < ActiveRecord::Base
  has_and_belongs_to_many :catalog_products, join_table: 'catalog_categories_catalog_products'
end 

CatalogProduct < ActiveRecord::Base
  has_and_belongs_to_many :catalog_categories, join_table: 'catalog_categories_catalog_products'
end 
  • プレフィックスではスコープも同様に考慮されるので、Catalog::CategoryCatalog::Product間のリレーションや、Catalog::CategoryCatalogProduct間のリレーションも同様に更新する必要があります。

5.5 Active Resource

Rails 4.0ではActive Resourceがgem化されました。この機能が必要な場合はActive Resource gem をGemfileに追加できます。

5.6 Active Model

  • Rails 4.0ではActiveModel::Validations::ConfirmationValidatorにエラーがアタッチされる方法が変更されました。確認バリデーションが失敗したときに、attributeではなく:#{attribute}_confirmationにアタッチされるようになりました。

  • Rails 4.0のActiveModel::Serializers::JSON.include_root_in_jsonのデフォルト値がfalseに変更されました。これにより、Active Model SerializersとActive Recordオブジェクトのデフォルトの動作が同じになりました。これにより、config/initializers/wrap_parameters.rbファイルの以下のオプションをコメントアウトしたり削除したりできるようになりました。

# Disable root element in JSON by default.
# ActiveSupport.on_load(:active_record) do
#   self.include_root_in_json = false 
# end

5.7 Action Pack

  • Rails 4.0からActiveSupport::KeyGeneratorが導入され、署名付きcookiesの生成と照合などに使用されるようになりました。Rails 3.xで生成された既存の署名付きcookiesは、既存のsecret_tokenはそのままにしてsecret_key_baseを新しく追加することで透過的にアップグレードされます。
  # config/initializers/secret_token.rb
  Myapp::Application.config.secret_token = 'existing secret token'
  Myapp::Application.config.secret_key_base = 'new secret key base'

注意:secret_key_baseを設定するのは、Rails 4.xへのユーザーベースの移行が100%完了し、Rails 3.xにロールバックする必要が完全になくなってからにしてください。これは、Rails 4.xの新しいsecret_key_baseを使用して署名されたcookiesにはRails 3.xのcookiesとの後方互換性がないためです。他のアップグレードが完全に完了するまでは、既存のsecret_tokenをそのままにしてsecret_key_baseを設定せず、非推奨警告を無視するという選択肢もあります。

外部アプリケーションやJavaScriptからRailsアプリケーションの署名付きセッションcookies (または一般の署名付きcookies) を読み出せる必要がある場合は、これらの問題を切り離すまではsecret_key_baseを設定しないでください。

  • Rails 4.0では、secret_key_baseが設定されているとcookieベースのセッションの内容が暗号化されます。Rails 3.xではcookieベースのセッションへの署名は行われますが暗号化は行われません。署名付きcookiesは、そのRailsアプリケーションで生成されたことが確認でき、不正が防止されるという意味では安全です。しかしセッションの内容はエンドユーザーから見えてしまいます。内容を暗号化することで懸念を取り除くことができ、パフォーマンスの低下もそれほどありません。

セッションcookiesを暗号化する方法の詳細についてはPull Request #9978 を参照してください。

  • Rails 4.0 ではActionController::Base.asset_pathオプションが廃止されました。代りにアセットパイプライン機能をご利用ください。

  • Rails 4.0ではActionController::Base.page_cache_extensionオプションが非推奨になりました。代りにActionController::Base.default_static_extensionをご利用ください。

  • Rails 4.0のAction PackからActionとPageのキャッシュ機能が取り除かれました。コントローラでcaches_actionを使用したい場合はactionpack-action_caching gemを、caches_pagesを使用したい場合はactionpack-page_caching gemをそれぞれGemfileに追加する必要があります。

  • Rails 4.0からXMLパラメータパーサーが取り除かれました。この機能が必要な場合はactionpack-xml_parser gemを追加する必要があります。

Rails 4.0 では、シンボルやprocがnilを返す場合の、デフォルトの layout ルックアップ設定が変更されました。動作を「no layout」にするには、nilではなくfalseを返すようにします。

  • Rails 4.0のデフォルトのmemcachedクライアントがmemcache-clientからdalliに変更されました。アップグレードするには、単にgem 'dalli'Gemfileに追加します。

  • Rails 4.0ではコントローラでのdom_idおよびdom_classメソッドの使用が非推奨になりました (ビューでの使用は問題ありません)。この機能が必要なコントローラではActionView::RecordIdentifierモジュールをインクルードする必要があります。

  • Rails 4.0ではlink_toヘルパーでの:confirmオプションが非推奨になりました。代わりにデータ属性を使用してください (例: data: { confirm: 'Are you sure?' })。link_to_iflink_to_unlessなどでも同様の対応が必要です。

  • Rails 4.0ではassert_generatesassert_recognizesassert_routingの動作が変更されました。これらのアサーションからはActionController::RoutingErrorの代りにAssertionが発生するようになりました。

  • Rails 4.0では、名前付きルートの定義が重複している場合にArgumentErrorが発生するようになりました。このエラーは、明示的に定義された名前付きルートやresourcesメソッドによってトリガされます。名前付きルートexample_pathが衝突している例を2つ示します。

  get 'one' => 'test#example', as: :example
  get 'two' => 'test#example', as: :example
  resources :examples
  get 'clashing/:id' => 'test#example', as: :example 

最初の例では、複数のルーティングで同じ名前を使用しないようにすれば回避できます。次の例では、onlyまたはexceptオプションをresourcesメソッドで使用することで、作成されるルーティングを制限することができます。詳細は Routing Guide を参照。

  • Rails 4.0ではunicode文字のルーティングの描出方法が変更されました。unicode文字を使用するルーティングを直接描出できるようになりました。既にこのようなルーティングを使用している場合は、以下の変更が必要です。
get Rack::Utils.escape('こんにちは'), controller: 'welcome', action: 'index'

上のコードは以下のように変更する必要があります。

get 'こんにちは', controller: 'welcome', action: 'index'
  • Rails 4.0でルーティングにmatchを使用する場合は、リクエストメソッドの指定が必須となりました。以下に例を示します。
  # Rails 3.x
  match '/' => 'root#index'

  # 上のコードは以下のように変更する必要があります。
  match '/' => 'root#index', via: :get

  # または
  get '/' => 'root#index'
  • Rails 4.0からActionDispatch::BestStandardsSupportミドルウェアが削除されました。<!DOCTYPE html>は既に http://msdn.microsoft.com/en-us/library/jj676915(v=vs.85).aspx の標準モードをトリガするようになり、ChromeFrameヘッダはconfig.action_dispatch.default_headersに移動されました。

アプリケーションコード内にあるこのミドルウェアへの参照はすべて削除する必要がありますのでご注意ください。例:

# 例外発生
config.middleware.insert_before(Rack::Lock, ActionDispatch::BestStandardsSupport)

環境設定も確認し、config.action_dispatch.best_standards_supportがある場合は削除します。

  • Rails 4.0のアセットのプリコンパイルでは、vendor/assetsおよびlib/assetsにある非JS/CSSアセットを自動的にはコピーしなくなりました。Railsアプリケーションとエンジンの開発者は、これらのアセットを手動でapp/assetsに置き、config.assets.precompileを設定してください。

  • Rails 4.0では、リクエストされたフォーマットがアクションで扱えなかった場合にActionController::UnknownFormatが発生するようになりました。デフォルトでは、この例外は406 Not Acceptable応答として扱われますが、この動作をオーバーライドすることができます。Rails 3では常に406 Not Acceptableが返されます。オーバーライドはできません。

  • Rails 4.0では、ParamsParserがリクエストパラメータをパースできなかった場合に一般的なActionDispatch::ParamsParser::ParseError例外が発生するようになりました。MultiJson::DecodeErrorのような低レベルの例外の代りにこの例外をレスキューすることができます。

  • Rails 4.0では、URLプレフィックスで指定されたアプリケーションにエンジンがマウントされている場合にSCRIPT_NAMEが正しく入れ子になるようになりました。今後はURLプレフィックスの上書きを回避するためにdefault_url_options[:script_name]を設定する必要はありません。

  • Rails 4.0ではActionDispatch::Integrationの導入に伴いActionController::Integrationが非推奨となりました。

  • Rails 4.0ではActionDispatch::IntegrationTestの導入に伴いActionController::IntegrationTestは非推奨となりました。

  • Rails 4.0ではActionDispatch::PerformanceTestの導入に伴いActionController::PerformanceTestが非推奨となりました。

  • Rails 4.0ではActionDispatch::Requestの導入に伴いActionController::AbstractRequestが非推奨となりました。

  • Rails 4.0ではActionDispatch::Requestの導入に伴いActionController::Requestが非推奨となりました。

  • Rails 4.0ではActionDispatch::Responseの導入に伴いActionController::AbstractResponseが非推奨となりました。

  • Rails 4.0ではActionDispatch::Responseの導入に伴いActionController::Responseが非推奨となりました。

  • Rails 4.0ではActionDispatch::Routingの導入に伴いActionController::Routingが非推奨となりました。

5.8 Active Support

Rails 4.0ではERB::Util#json_escapeのエイリアスjが廃止されました。このエイリアスjは既にActionView::Helpers::JavaScriptHelper#escape_javascriptで使用されているためです。

5.8.1 キャッシュ

Rails 3系とRails 4.0とで、キャッシュ用のメソッドが変更されましたキャッシュの名前空間を変更し、コールドキャッシュ (cold cache) を使って更新してください。

5.9 ヘルパーの読み込み順序

Rails 4.0では複数のディレクトリからのヘルパーの読み込み順が変更されました。以前はすべてのヘルパーをいったん集めてからアルファベット順にソートしていました。Rails 4.0にアップグレードすると、ヘルパーは読み込まれたディレクトリの順序を保持し、ソートは各ディレクトリ内でのみ行われます。helpers_pathパラメータを明示的に使用している場合を除いて、この変更はエンジンからヘルパーを読み込む方法にしか影響しません。ヘルパー読み込みの順序に依存している場合は、アップグレード後に正しいメソッドが使用できているかどうかを確認する必要があります。エンジンが読み込まれる順序を変更したい場合は、config.railties_order= メソッドを使用できます。

5.10 Active Record ObserverとAction Controller Sweeper

Active Record ObserverAction Controller Sweeperrails-observers gemに切り出されました。これらの機能が必要な場合はrails-observers gemを追加してください。

5.11 sprockets-rails

  • assets:precompile:primaryおよびassets:precompile:allは削除されました。assets:precompileを代りに使用してください。
  • config.assets.compressオプションは、たとえば以下のようにconfig.assets.js_compressor に変更する必要があります。
config.assets.js_compressor = :uglifier

5.12 sass-rails

  • 引数を2つ使用するasset-urlは非推奨となりました。たとえば、asset-url("rails.png", image)asset-url("rails.png")とする必要があります。

6 Rails 3.1からRails 3.2へのアップグレード

Railsアプリケーションのバージョンが3.1よりも古い場合、まず3.1へのアップグレードを完了してからRails 3.2へのアップグレードを開始してください。

以下の変更は、Rails 3.2.xにアップグレードするためのものです。

6.1 Gemfile

Gemfileを以下のように変更します。

gem 'rails', '3.2.21'

group :assets do
  gem 'sass-rails',   '~> 3.2.6'
  gem 'coffee-rails', '~> 3.2.2'
  gem 'uglifier',     '>= 1.0.3'
end

6.2 config/environments/development.rb

development環境にいくつかの新しい設定を追加する必要があります。

# Active Recordのモデルをマスアサインメントから保護するために例外を発生する
config.active_record.mass_assignment_sanitizer = :strict

# クエリの実行計画 (クエリプラン) を現在より多く出力する
# (SQLite、MySQL、PostgreSQLで動作)
config.active_record.auto_explain_threshold_in_seconds = 0.5

6.3 config/environments/test.rb

mass_assignment_sanitizer設定をconfig/environments/test.rbにも追加する必要があります。

# Active Recordのモデルをマスアサインメントから保護するために例外を発生する
config.active_record.mass_assignment_sanitizer = :strict

6.4 vendor/plugins

vendor/plugins はRails 3.2で非推奨となり、Rails 4.0では完全に削除されました。Rails 3.2へのアップグレードでは必須ではありませんが、今のうちにプラグインをgemにエクスポートしてGemfileに追加するのがよいでしょう。理由があってプラグインをgemにしないのであれば、プラグインをlib/my_plugin/*に移動し、適切な初期化の記述をconfig/initializers/my_plugin.rbに書いてください。

6.5 Active Record

:dependent => :restrictオプションはbelongs_toから削除されました。関連付けられたオブジェクトがある場合にこのオブジェクトを削除したくない場合は、:dependent => :destroyを設定し、関連付けられたオブジェクトのdestroyコールバックとの関連付けがあるかどうかを確認してからfalseを返すようにします。

7 Rails 3.0からRails 3.1へのアップグレード

Railsアプリケーションのバージョンが3.0より前の場合、まず3.0へのアップグレードを完了してからRails 3.1へのアップグレードにとりかかってください。

以下の変更は、Rails 3.1.xの最新版であるRails 3.1.12にアップグレードするためのものです。

7.1 Gemfile

Gemfileを以下のように変更します。

gem 'rails', '3.1.12'
gem 'mysql2' 

# 新しいアセットパイプラインで必要
group :assets do
  gem 'sass-rails',   '~> 3.1.7'
  gem 'coffee-rails', '~> 3.1.1'
  gem 'uglifier',     '>= 1.0.3'
end

# Rails 3.1からjQueryがデフォルトのJavaScriptライブラリになる
gem 'jquery-rails'

7.2 config/application.rb

アセットパイプラインを使用するために以下の変更が必要です。

config.assets.enabled = true
config.assets.version = '1.0'

Railsアプリケーションでリソースのルーティングに"/assets"ルートを使用している場合、コンフリクトを避けるために以下の変更を加えます。

# '/assets'のデフォルト
config.assets.prefix = '/asset-files'

7.3 config/environments/development.rb

RJS の設定config.action_view.debug_rjs = trueを削除してください。

アセットパイプラインを有効にしている場合は以下の設定を追加します。

# 開発環境ではアセットを圧縮しない
config.assets.compress = false

# アセットで読み込んだ行を展開する
config.assets.debug = true

7.4 config/environments/production.rb

以下の変更はほとんどがアセットパイプライン用です。詳細については アセットパイプライン ガイドを参照してください。

# JavaScriptとCSSを圧縮する
config.assets.compress = true

# プリコンパイル済みのアセットが見当たらない場合にアセットパイプラインにフォールバックしない
config.assets.compile = false

# アセットURLのダイジェストを生成する
config.assets.digest = true

# Rails.root.join("public/assets")へのデフォルト
# config.assets.manifest = 該当するパス

# 追加のアセット (application.js、application.cssおよびすべての非JS/CSSが追加済み) をプリコンパイルする
# config.assets.precompile += %w( admin.js admin.css )

# アプリケーションへのすべてのアクセスを強制的にSSLにし、Strict-Transport-Securityとセキュアクッキーを使用する
# config.force_ssl = true

7.5 config/environments/test.rb

テスト環境に以下を追加することでテストのパフォーマンスが向上します。

# Cache-Controlを使用するテストで静的アセットサーバーを構成し、パフォーマンスを向上させる
config.public_file_server.enabled = true
config.public_file_server.headers = {
  'Cache-Control' => 'public, max-age=3600'
}

7.6 config/initializers/wrap_parameters.rb

ネストしたハッシュにパラメータを含めたい場合は、このファイルに以下のコンテンツを含めて追加します。新しいアプリケーションではこれがデフォルトになります。

# このファイルを変更後サーバーを必ず再起動してください。
# このファイルにはActionController::ParamsWrapper用の設定が含まれており
# デフォルトでオンになっています。

# JSON用にパラメータをラップします。:formatに空配列を設定することで無効にできます。
ActiveSupport.on_load(:action_controller) do
  wrap_parameters format: [:json]
end

# JSONのルート要素をデフォルトで無効にする
ActiveSupport.on_load(:active_record) do
  self.include_root_in_json = false
end

7.7 config/initializers/session_store.rb

何らかの新しいセッションキーを設定するか、すべてのセッションを削除するかのどちらかにする必要があります。

# config/initializers/session_store.rbに以下を設定する
AppName::Application.config.session_store :cookie_store, key: 'SOMETHINGNEW'

または

$ bin/rake db:sessions:clear

7.8 ビューのアセットヘルパー参照から:cacheオプションと:concatオプションを削除する

  • Asset Pipelineの:cacheオプションと:concatは廃止されました。ビューからこれらのオプションを削除してください。