本章では、アプリケーションで使われているRuby on Railsのバージョンを、新しいバージョンにアップグレードする際の手順について示します。アップグレードの手順は、Railsのバージョンごとに記載されています。
throw(:abort)でコールバックチェーンを停止するmysqlデータベースアダプタのサポートを終了railsを使うことActionController::Parametersは今後HashWithIndifferentAccessを継承しないprotect_from_forgeryは今後デフォルトでprepend: falseに設定されるActionView::Helpers::RecordTagHelperは外部のgemに移動(record_tag_helper)protected_attributes gemのサポートを終了activerecord-deprecated_finders gemのサポートを終了ActiveSupport::TestCaseでのテストは今後デフォルトでランダムに実行されるActionController::Live はConcernに変更された<script> タグにCSRF保護を実施config/secrets.ymlreturnを利用できなくなるActiveSupport::Callbacksでは明示的にブロックを利用すること言うまでもないことですが、既存のアプリケーションをアップグレードする際には、アップグレードの目的を明確にする必要があります。新しいバージョンのうちどの機能が必要になるのか、既存のコードのサポートがどのぐらい困難になるのか、アップグレードに必要な時間とスキルはどれほど必要かなど、いくつもの要素を調整しなければなりません。
アップグレード後にアプリケーションが正常に動作していることを確認する方法としては、良いテストカバレッジをアップグレード前に準備しておくのが最善です。アプリケーションを一気に検査する自動テストがないと、変更点をすべて手動で確認しなければならず膨大な時間がかかってしまいます。Railsのようなアプリケーションの場合、これはアプリケーションのあらゆる機能を一つ残らず確認しなければならないということです。アップグレードの実施は、テストカバレッジをきちんと準備してから行なうよう、くれぐれもお願いします。
Railsのバージョンを変更する場合、マイナーバージョンを1つずつゆっくりと変更して、非推奨機能の警告をすべて確認・利用するのが最善の方法であると言えます。言い換えると、アップグレードを急ぐあまりバージョンをスキップするべきではありません。Railsのバージョン番号は「メジャー番号.マイナー番号.パッチ番号」の形式を取ります。メジャーバージョンやマイナーバージョンが変更される場合、公開APIの変更によるエラーがアプリケーションで発生する可能性があります。パッチバージョンはバグ修正のみが含まれ、公開API変更は含まれません。
アップグレードは以下の手順で行います。
上の手順を繰り返して、最終的にRailsを目的のバージョンにアップグレードします。バージョンを移行するたびに、Gemfile内のRailsバージョン番号を変更(これに伴い、他のgemのバージョン変更が必要になることもあります)し、bundle update を実行する必要があります。続いて、以下のアップデートタスクを実行して設定ファイルをアップデートし、テストを実行します。
リリース済みのRailsバージョンのリストはここで確認できます。
Railsは、そのバージョンがリリースされた時点で最新のバージョンの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をお使いください。
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 ...
予期しなかった変更が発生した場合は、必ず差分を十分にチェックしてください。
新しいバージョンのRailsでは前のバージョンとデフォルトの設定が異なることがあります。しかし上述の手順に従うことで、アプリケーションを引き続き従来バージョンのRailsのデフォルト設定で動かせることもあります(config/application.rbのconfig.load_defaultsの値が変更されていないため)。
updateタスクでは、アプリケーションを新しいデフォルト設定に1つずつアップグレードできるように、config/initializers/new_framework_defaults.rbファイルが作成されます。アプリケーションを新しいデフォルト設定で動かせる準備が整ったら、このファイルを削除してconfig.load_defaultsの値を反転できます。
Rails 6.0の変更点の詳細はリリースノートを参照してください。
WebpackerはRails 6におけるデフォルトのJavaScriptコンパイラですが、アプリケーションを以前のバージョンからアップグレードした場合は自動的には有効になりません。
Webpackerを使いたい場合は、以下をGemfileに追記し、rails webpacker:installコマンドを実行してインストールしてください。
gem "webpacker"
rails webpacker:install
コントローラのforce_sslメソッドは非推奨化され、Rails 6.1で削除される予定です。config.force_sslを有効にしてアプリ全体でHTTPS接続を強制することをおすすめします。特定のエンドポイントのみをリダイレクトしないようにする必要がある場合は、config.ssl_optionsで振る舞いを変更できます。
Railsではセキュリティ向上のため、または署名済み暗号化済みcookie値のpurpose情報を埋め込みます。
これにより、Railsはcookieの署名済み/暗号化済みの値をコピーして別のcookieで流用することを阻止できるようになります。
新たに埋め込まれるこのpurpose情報によって、Rails 6.0のcookieはそれより前のバージョンのcookieとの互換性が失われます。
cookieを引き続きRails 5.2以前でも読み取れるようにする必要がある場合や、6.0のデプロイを検証中で前のバージョンに戻せるようにしたい場合は、Rails.application.config.action_dispatch.use_cookies_with_metadataにfalseを設定してください。
Action Cable JavaScriptパッケージがCoffeeScriptからES2015に置き換えられ、ソースコードをnpmディストリビューションでパブリッシュできるようになりました。
今回のリリースでは、Action Cable JavaScript APIの選択可能な部分に若干のbreaking changesが生じます。
ActionCableのプロパティからActionCable.adaptersのプロパティに移動しました。これらのアダプタを設定している場合は、以下の変更が必要です。- ActionCable.WebSocket = MyWebSocket + ActionCable.adapters.WebSocket = MyWebSocket
- ActionCable.logger = myLogger + ActionCable.adapters.logger = myLogger
ActionCable.startDebugging()メソッドとActionCable.stopDebugging()メソッドが削除され、ActionCable.logger.enabledに置き換えられました。これらのメソッドを使っている場合は、以下の変更が必要です。- ActionCable.startDebugging() + ActionCable.logger.enabled = true
- ActionCable.stopDebugging() + ActionCable.logger.enabled = false
ActionDispatch::Response#content_typeがContent-Typeヘッダーを変更せずに返すようになった従来は、ActionDispatch::Response#content_typeの戻り値にcharsetパートが含まれていませんでした。
この振る舞いは変更され、従来省略されていたcharsetパートも含まれるようになりました。
MIMEタイプだけが欲しい場合は、代わりにActionDispatch::Response#media_typeをお使いください。
変更前:
resp = ActionDispatch::Response.new(200, "Content-Type" => "text/csv; header=present; charset=utf-16") resp.content_type #=> "text/csv; header=present"
変更後:
resp = ActionDispatch::Response.new(200, "Content-Type" => "text/csv; header=present; charset=utf-16") resp.content_type #=> "text/csv; header=present; charset=utf-16" resp.media_type #=> "text/csv"
Rails 6のデフォルト設定では、CRubyでzeitwerkのオートローディングモードが有効になります。
# config/application.rb config.load_defaults "6.0"
オートローディングモードでは、オートロード、再読み込み、eager loadingをZeitwerkで管理します。
一般に、アプリケーションでZeitwerk APIの利用が直接必要になることはありません。Railsは、config.autoload_pathsやconfig.cache_classesといった既存の約束事に沿ってセットアップを行います。
アプリケーションはこのインターフェイスを遵守すべきですが、実際のZeitwerkローダーオブジェクトに以下のようにアクセスできます。
Rails.autoloaders.main
上は、たとえばSTI(単一テーブル継承)をプリロードする必要がある場合や、カスタムのinflectorを設定する必要が生じた場合には役立つことがあるでしょう。
アップグレードしたアプリケーションのオートロードが正しく動いていれば、プロジェクトの構成はほとんど互換が取れているはずです。
ただしclassicモードは、見つからない定数名からファイル名を推測しますが(underscore)、zeitwerkモードはファイル名から定数名を推測します(camelize)。特に略語がからむ場合、これらのヘルパーの動作が互いにきれいに逆になるとは限りません。たとえば、"FOO".underscoreは"foo"になりますが、 "foo".camelizeは"FOO"ではなく"Foo"になります。
互換性については、以下のようにzeitwerk:checkタスクでチェックできます。
bin/rails zeitwerk:check
require_dependencyについてrequire_dependencyの既知のユースケースはすべて排除されました。自分のプロジェクトをgrepしてrequire_dependencyを削除してください。
アプリケーションでSTI(単一テーブル継承)が使われている場合は、定数の自動読み込みと再読み込み(Zeitwerkモード)ガイドの該当セクションをご覧ください。
クラス定義やモジュール定義で、定数パスを安定して使えるようになりました。
# このクラスの本文のオートロードがRubyのセマンティクスと一致するようになった class Admin::UsersController < ApplicationController # ... end
ここで知っておいていただきたいのは、classicモードのオートローダーでは、実行順序によっては以下のコードのFoo::Wadusをオートロードできてしまう場合があるということです。
class Foo::Bar Wadus end
上のFooはネストしていないのでRubyのセマンティクスと一致せず、zeitwerkではまったく動かなくなります。こうしたエッジケースが見つかったら、以下のように完全修飾名のFoo::Wadusを使えます。
class Foo::Bar Foo::Wadus end
または、以下のようにFooでネストすることもできます
module Foo class Bar Wadus end end
以下のような標準的な構造は、オートロードもeager loadも可能です。
app/models app/models/concerns
上は、(オートロードパスに属するので)app/models/concernsがルートディレクトリであると仮定され、名前空間としては無視されます。したがって、app/models/concerns/foo.rbはConcerns::FooではなくFooと定義すべきです。
Concerns::名前空間は、classicモードのオートローダーでは実装の副作用によって動作していましたが、これは意図した動作ではありませんでした。Concerns::を使っているアプリケーションがzeitwerkモードで動くようにするには、こうしたクラスやモジュールをリネームする必要があります。
appがある場合プロジェクトによっては、API::Baseを定義するためにapp/api/base.rbのようなものが欲しい場合があります。classicモードではこれを行うためにオートロードパスにappを追加します。Railsはappの全サブディレクトリをオートロードに自動的に追加するので、ネストしたルートディレクトリがある状況がもうひとつ存在することになり、セットアップが機能しなくなります。上述したのと似た原則がconcernsにも当てはまります。
そうした構造を維持したい場合は、イニシャライザで以下のようにそのサブディレクトリをオートロードパスから削除する必要が生じます。
ActiveSupport::Dependencies.autoload_paths.delete("#{Rails.root}/app/api")
あるファイルの中で名前空間が1つ定義されているとします(ここではHotel)。
app/models/hotel.rb # Defines Hotel. app/models/hotel/pricing.rb # Defines Hotel::Pricing.
このHotelという定数の定義には、必ずclassキーワードまたはmoduleキーワードを使わなければなりません。次の例をご覧ください。
class Hotel end
上は問題ありません。
しかし以下はどちらも動きません。
Hotel = Class.new
Hotel = Struct.new
どちらも、Hotel::Pricingなどの子オブジェクトを探索できなくなります。
この制約は、明示的な名前空間にのみ適用されます。名前空間を定義しないクラスやモジュールであれば、そうしたイディオムで定義することもできます。
classicモードでは、同じトップレベルに複数の定数を定義して、それらをすべて再読み込みすることが技術的には可能でした。以下の例をご覧ください。
# app/models/foo.rb class Foo end class Bar end
上でFooをオートロードすると、Barをオートロードできなかった場合にもBarをオートロード済みとマーキングすることがありました。このようなコードはzeitwerkでは対象外です。Barはそれ専用のbar.rbというファイルに移すべきです。「1つのファイルには1つの定数だけ」となります。
この影響を受けるのは、上の例のように「同じトップレベルにある」複数の定数だけです。ネストの内側にあるクラスやモジュールは影響を受けません。以下の例をご覧ください。
# app/models/foo.rb class Foo class InnerClass end end
アプリケーションでFooを再読み込みすれば、Foo::InnerClassも再読み込みされます。
test環境についてspring gemは、アプリケーションのコードが変更されると再読み込みします。test環境では、そのために再読み込みを有効にしておく必要があります。
# config/environments/test.rb config.cache_classes = false
有効にしておかないと、以下のエラーが表示されます。
reloading is disabled because config.cache_classes is true
Bootsnapのバージョンは1.4.2以上にするべきです。
また、Ruby 2.5を実行中は、インタプリタのバグの関係で、iseqキャッシュを無効にする必要があります。その場合はBootsnap 1.4.4以上に依存させるようにしてください。
config.add_autoload_paths_to_load_path以下の新しい設定は、後方互換性のためデフォルトでtrueになっていますが、これを使って$LOAD_PATHに追加されるオートロードパスを減らせます。
config.add_autoload_paths_to_load_path
これは、ほとんどのアプリケーションにとって合理的です(app/models内のファイルをrequireするような行為は決してすべきではないので)。しかも、Zeitwerkは内部で絶対パスだけを使います。
この新しい設定を無効にすれば、$LOAD_PATHの探索を最適化して(つまりチェックするディレクトリを減らして)、Bootsnapの動作を軽くしてメモリ消費量を削減できます。Bootsnapがそうしたディレクトリのインデックスをビルドする必要がなくなるからです。
classicモードの定数オートロードはスレッド安全ではありません。Railsには、オートロードが有効な状態でWebのリクエストをスレッド安全にする(これはdevelopmentモードでよくあることです)などのためのインプレースのロックがあるにもかかわらずです。
zeitwerkモードの定数オートロードは、スレッド安全です。たとえば、runnerコマンドで実行されるマルチスレッドでもオートロードが可能です。
以下のような設定は要注意です。
config.autoload_paths += Dir["#{config.root}/lib/**/"]
config.autoload_pathsのあらゆる要素は、トップレベルの名前空間(Object)を表すべきなので、ネストできなくなります(前述のconcernsディレクトリは例外)。
この修正は、ワイルドカードを削除するだけでできます。
config.autoload_paths << "#{config.root}/lib"
classicの場合、たとえばapp/models/foo.rbでBarを定義すると、そのファイルをオートロードできなくなりますが、eager loading(一括読み込み)は盲目的にファイルを再帰読み込みするため、可能です。この挙動のため、テストでeager loadingを最初に行うとその後の実行でオートロードが失敗し、エラーの原因となる可能性があります。
zeitwerkモードの場合、どちらの読み込みモードも一貫するので、失敗やエラーは同一のファイルで発生するようになります。
アプリケーションはRails 6のデフォルトを読み込みますが、以下のようにconfig.autoloaderを設定することでclassicモードのオートローダを使うこともできます。
# config/application.rb config.load_defaults "6.0" config.autoloader = :classic
Rails 6アプリケーションでclassicオートローダーを使う場合は、スレッド安全性上の懸念があるため、development環境ではWebサーバーやバックグラウンド処理のconcurrency levelを1に設定することをおすすめします。
Rails 5.2では、has_many_attachedで宣言された添付ファイル(attachment)のコレクションへの代入は、新しいファイルの追加(append)操作になります。
class User < ApplicationRecord has_many_attached :highlights end user.highlights.attach(filename: "funky.jpg", ...) user.higlights.count # => 1 blob = ActiveStorage::Blob.create_after_upload!(filename: "town.jpg", ...) user.update!(highlights: [ blob ]) user.highlights.count # => 2 user.highlights.first.filename # => "funky.jpg" user.highlights.second.filename # => "town.jpg"
Rails 6.0のデフォルト設定では、添付ファイルのコレクションへの代入は、追加ではなく既存ファイルの置き換え操作になります。これにより、Active Recordでコレクションの関連付けに代入するときの振る舞いと一貫するようになります。
user.highlights.attach(filename: "funky.jpg", ...) user.highlights.count # => 1 blob = ActiveStorage::Blob.create_after_upload!(filename: "town.jpg", ...) user.update!(highlights: [ blob ]) user.highlights.count # => 1 user.highlights.first.filename # => "town.jpg"
既存のものを削除せずに添付ファイルを新たに追加するには、#attachが利用できます。
blob = ActiveStorage::Blob.create_after_upload!(filename: "town.jpg", ...) user.highlights.attach(blob) user.highlights.count # => 2 user.highlights.first.filename # => "funky.jpg" user.highlights.second.filename # => "town.jpg"
設定でconfig.active_storage.replace_on_assign_to_manyをtrueにすることで、新しいデフォルトの振る舞いを選択できます。従来の振る舞いはRails 6.1で非推奨化され、その後のリリースで削除される予定です。
Rails 5.2 の変更点の詳細はリリースノートを参照してください。
Rails 5.2 では新規作成したアプリケーションのGemfileに bootsnap gem が追加されました。boot.rbのapp:updateコマンドを実行するとセットアップが行われます。使いたい場合は、Gemfileにbootsnap gemを追加してください。boot.rbを変更し、bootsnapを使わないようにすることもできます。
セキュリティ向上のため、Railsでは暗号化または署名付きcookieに有効期限情報を埋め込むようになりました。
有効期限情報が付与されたcookieは、Rails 5.1 以前のバージョンとの互換性はありません。
Rails 5.1 以前で新しいcookieを読み込みたい場合、もしくは Rails 5.2 でうまくデプロイできるか確認したい場合は (必要に応じてロールバックできるようにしたい場合は) Rails.application.config の action_dispatch.use_authenticated_cookie_encryption を false に設定してください。
Rails 5.1 の変更点の詳細はリリースノートを参照してください。
HashWithIndifferentAccessが弱く非推奨化されたアプリケーションでトップレベルのHashWithIndifferentAccessクラスを使っている場合、すぐでなくてもよいのでActiveSupport::HashWithIndifferentAccessに置き換えてください。
これは「弱い非推奨化」であり、しばらくは正常に動作し、非推奨警告も表示されません。ただし、この定数は将来削除されます。
また、こうしたオブジェクトのダンプを含むかなり古いYAMLドキュメントがある場合は、YAMLを再度読み込み/ダンプして、正しい定数が参照されるようにしておく必要があるかもしれません。また、読み込みについては今後も利用できます。
application.secretsですべてのキーをシンボルとして読み込むようになったconfig/secrets.ymlに保存されているアプリケーションの設定がネストしている場合、すべてのキーがシンボルとして読み込まれます。このため、文字列による設定へのアクセス方法を以下のように変更する必要があります。
変更前:
Rails.application.secrets[:smtp_settings]["address"]
変更後:
Rails.application.secrets[:smtp_settings][:address]
render :textとrender :nothingサポートの削除ビューのrender :textは今後利用できません。MIME typeを「text/plain」にしてテキストをレンダリングする新しい方法はrender :plainを使うことです。
render :nothingも同様に削除されますので、今後ヘッダーのみのレスポンスを返すにはheadメソッドをお使いください。
例: head :okは、bodyをレンダリングせずにresponse 200を返します。
Rails 5.0 の変更点の詳細はリリースノートを参照してください。
Ruby on Rails 5.0以降は、バージョン2.2.2以降の Ruby だけをサポートします。 Rubyのバージョンが2.2.2以降であることを確認してから手順を進めてください。
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を継承するように変更し、動作を確認してください。
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をRails5.0にアップグレードした場合、こうしたコールバックでfalseが返ったときに従来同様コールバックチェーンは停止しますが、この変更にともなう非推奨警告が表示されます。
この変更内容とその影響を十分理解しているのであれば、config/application.rbに以下の記述を追加して非推奨警告をオフにできます。
ActiveSupport.halt_callback_chains_on_return_false = false
Active Supportのコールバックはこのオプションの影響を受けないことにご注意ください。Active Supportのチェーンはどのような値が返っても停止しません。
詳しくは#17227を参照してください。
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を参照してください。
rails-controller-testingに移転assignsメソッドとassert_templateメソッドはrails-controller-testing gemに移転しました。これらのメソッドを引き続きコントローラのテストで使いたい場合は、Gemfileにgem 'rails-controller-testing'を追加してください。
テストでRspecを使っている場合は、このgemのドキュメントで必須となっている追加の設定方法もご確認ください。
ファイルアップロードのテストでActionDispatch::Http::UploadedFileクラスを使っている場合、Rack::Test::UploadedFileクラスに変更する必要があります。
詳しくは#26404を参照してください。
今後Railsがproduction環境で起動されると、自動読み込みがデフォルトで無効になります。
アプリケーションの一括読み込み(eager loading)は起動プロセスに含まれています。このため、トップレベルの定数についてはファイルをrequireしなくても問題なく利用でき、従来と同様に自動読み込みされます。
トップレベルより下で、実行時にのみ有効にする定数(通常のメソッド本体など)を定義した場合も、起動時に一括読み込みされるので問題なく利用できます。
ほとんどのアプリケーションでは、この変更に関して特別な対応は不要です。めったにないと思われますが、productionモードで動作するアプリケーションで自動読み込みが必要な場合は、Rails.application.config.enable_dependency_loadingをtrueに設定してください。
RailsのActiveModel::Serializers::Xmlはactivemodel-serializers-xml gemに移転しました。アプリケーションで今後もXMLシリアライズを使うには、Gemfileにgem 'activemodel-serializers-xml'を追加してください。
mysqlデータベースアダプタのサポートを終了Rails 5で古いmysqlデータベース アダプタのサポートが終了しました。原則としてmysql2をお使いください。今後古いアダプタのメンテナンス担当者が決まった場合、アダプタは別のgemに切り出されます。
Rails 5が必要とするRuby 2.2では、debuggerはサポートされていません。代わりに、今後はbyebugをお使いください。
railsを使うことRails 5では、rakeに代わってbin/railsでタスクやテストを実行できるようになりました。原則として、多くのタスクやテストはrakeでも引き続き実行できますが、一部のタスクやテストは完全にbin/railsに移行しました。
今後テストの実行にはrails testをお使いください。
rake dev:cacheはrails dev:cacheに変更されました。
アプリケーションディレクトリの下でrailsを実行すると、利用可能なコマンドリストを表示できます。
ActionController::Parametersは今後HashWithIndifferentAccessを継承しないアプリケーションでparamsを呼び出すと、今後はハッシュではなくオブジェクトが返ります。現在使っているパラメーターがRailsで既に利用できている場合、変更は不要です。permitted?の状態にかかわらずハッシュを読み取れることが前提のメソッド(sliceメソッドなど)にコードが依存している場合、まずアプリケーションをアップグレードしてpermitを指定し、それからハッシュに変換する必要があります。
params.permit([:proceed_to, :return_to]).to_h
protect_from_forgeryは今後デフォルトでprepend: falseに設定されるprotect_from_forgeryは今後デフォルトでprepend: falseに設定されます。これにより、protect_from_forgeryはアプリケーションで呼び出される時点でコールバックチェーンに挿入されます。protect_from_forgeryを常に最初に実行したい場合は、アプリケーションの設定でprotect_from_forgery prepend: trueを指定する必要があります。
拡張子がテンプレートハンドラになっていないファイルは、今後rawハンドラで出力されるようになります。従来のRailsでは、このような場合にはERBテンプレートハンドラで出力されました。
ファイルをrawハンドラで出力したくない場合は、ファイルに明示的に拡張子を与え、適切なテンプレート ハンドラで処理されるようにしてください。
テンプレート依存関係をワイルドカードマッチングで指定できるようになりました。以下のテンプレートを例に説明します。
<% # 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/* %>
ActionView::Helpers::RecordTagHelperは外部のgemに移動(record_tag_helper)content_tag_forとdiv_forが削除され、content_tagのみの利用が推奨されます。これらの古いメソッドを使い続けたい場合、record_tag_helper gemをGemfileに追加してください。
gem 'record_tag_helper', '~> 1.0'
詳しくは#18411を参照してください。
protected_attributes gemのサポートを終了protected_attributes gemのサポートはRails 5で終了しました。
activerecord-deprecated_finders gemのサポートを終了activerecord-deprecated_finders gemのサポートはRails 5で終了しました。
ActiveSupport::TestCaseでのテストは今後デフォルトでランダムに実行されるアプリケーションのテストのデフォルトの実行順序は、従来の:sortedから:randomに変更されました。:sortedに戻すには以下のオプションを指定します。
# config/environments/test.rb Rails.application.configure do config.active_support.test_order = :sorted end
ActionController::Live はConcernに変更されたコントローラに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
belongs_toはデフォルトオプションで必須関連付けが存在しない場合、belongs_toでバリデーションエラーが発生するようになりました。
なお、この機能は関連付けごとにoptional: trueを指定してオフにできます。
新しいアプリケーションでは、このデフォルト設定が自動で有効になります。この設定を既存のアプリケーションに追加するには、イニシャライザでこの機能をオンにする必要があります
config.active_record.belongs_to_required_by_default = true
Rails 5 では、JavaScriptで作成されたフォームによるコードインジェクション攻撃に対応するため、フォーム単位でのCSRFトークンをサポートします。このオプションがオンの場合、アクションやメソッド固有のCSRFトークンがアプリケーションのフォームごとに個別に生成されるようになります。
config.action_controller.per_form_csrf_tokens = true
アプリケーションで、CSRF防御の一環としてHTTP Originヘッダによるサイトの出自チェックを設定できるようになりました。以下の設定をtrueにすることで有効になります。
config.action_controller.forgery_protection_origin_check = true
デフォルトのメーラー キュー名はmailersです。新しい設定オプションを使うと、キュー名をグローバルに変更できます。以下の方法で設定します。
config.action_mailer.deliver_later_queue_name = :new_queue_name
設定ファイルのconfig.action_mailer.perform_cachingで、Action Mailerのビューでキャッシュをサポートするかどうかを指定できます。
config.action_mailer.perform_caching = true
db:structure:dumpの出力形式のカスタマイズschema_search_pathや、その他のPostgreSQLエクステンションを使っている場合、スキーマのダンプ方法を指定できます。以下のように:allを指定するとすべてのダンプが生成され、:schema_search_pathを指定するとスキーマ検索パスからダンプが生成されます。
config.active_record.dump_schemas = :all
サブドメインで HSTS(HTTP Strict Transport Security)を有効にするには、以下の設定を使います。
config.ssl_options = { hsts: { subdomains: true } }
Ruby 2.4を利用している場合、to_timeの呼び出しでレシーバのタイムゾーンを保存できます。
ActiveSupport.to_time_preserves_timezone = false
Rails 5.0では、JSON属性やJSONB属性がシリアライズ/デシリアライズされる方法が変更されました。これにより、たとえばActive RecordでStringに等しいカラムを設定しても、その文字列をHashに変換せず、その文字列のみを返すようになります。この変更はモデル同士がやりとりするコードに限定されず、db/schema.rbで設定される:defaultカラムにも影響します。Stringに等しいカラムを設定せず、Hashを渡すようにしてください。これにより、JSON文字列への変換や逆変換が自動で行われるようになります。
最初に、Gemfileのdevelopmentグループにgem 'web-console', '~> 2.0'を追加し、bundle installを実行してください (このgemはRailsを過去のバージョンからアップグレードした場合には含まれないので、手動で追加する必要があります)。gemのインストール完了後、<%= console %>などのコンソールヘルパーへの参照をビューに追加するだけで、どのビューでもコンソールを利用できるようになります。このコンソールは、development環境のビューで表示されるすべてのエラーページにも表示されます。
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を参照してください。
現在のActive Recordでは、after_rollbackやafter_commitコールバックでの例外を抑制しており、例外時にはログ出力のみが行われます。次のバージョンからは、これらのエラーは抑制されなくなりますのでご注意ください。今後は他のActive Recordコールバックと同様のエラー処理を行います。
after_rollbackコールバックやafter_commitコールバックを定義すると、この変更にともなう非推奨警告が表示されるようになりました。この変更内容を十分理解し、受け入れる準備ができているのであれば、config/application.rbに以下の記述を行なうことで非推奨警告が表示されないようにすることができます。
config.active_record.raise_in_transactional_callbacks = true
詳しくは、#14488および#16537を参照してください。
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
serialize :metadata, JSONなどのカスタムコーダーを使っている場合に、シリアル化属性 (serialized attribute) にnilを割り当てると、コーダー内でnil値を渡すのではなく、データベースにNULLとして保存されるようになりました (JSONコーダーを使っている場合の"null"など)。
Rails 5のproduction環境では、デフォルトのログレベルが:infoから:debugに変更される予定です。現在のログレベルを変更したくない場合はproduction.rbに以下の行を追加してください。
# `:info`を指定すると現在のデフォルト設定が使われ、 # `:debug`を指定すると今後のデフォルト設定が使われる config.log_level = :info
after_bundleRailsテンプレートを利用し、かつすべてのファイルを (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
アプリケーションでHTMLの断片をサニタイズする方法に新しい選択肢が1つ増えました。従来の伝統的なHTMLスキャンによるサニタイズは公式に非推奨化されました。現在推奨される方法はRails HTMLサニタイザです。
これにより、sanitize、sanitize_css、strip_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'
assert_tagなどを含むTagAssertionsモジュールは非推奨になりました。今後推奨されるのは、ActionViewからrails-dom-testing gemに移行したSelectorAssertionsモジュールのassert_selectメソッドです。
SSL攻撃を緩和するために、form_authenticity_tokenがマスクされるようになりました。これにより、このトークンはリクエストごとに変更されます。トークンの検証はマスク解除 (unmasking)とそれに続く復号 (decrypting) によって行われます。この変更が行われたことにより、railsアプリケーション以外のフォームから送信される、静的なセッションCSRFトークンに依存するリクエストを検証する際には、このマスク済み真正性トークンのことを常に考慮する必要がありますのでご注意ください。
従来は、メーラークラスでメーラーメソッドを呼び出すと、該当するインスタンスメソッドが直接実行されました。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
マイグレーションDSLが拡張され、外部キー定義をサポートするようになりました。Foreigner gemを使っていた場合は、この機会に削除するとよいでしょう。Railsの外部キーサポートは、Foreignerの全機能ではなく、一部のみである点にご注意ください。このため、Foreignerの定義を必ずしもRailsのマイグレーションDSLに置き換えられないことがあります。
移行手順は次のとおりです。
Gemfileのgem "foreigner"を削除します。bundle installを実行します。bin/rake db:schema:dumpを実行します。db/schema.rbにすべて含まれていることを確認します。<script> タグにCSRF保護を実施これを行わないと、「なぜかテストがとおらない...orz」「<script>ウィジェットがおかしい!」などという結果になりかねません。
JavaScriptレスポンスを伴うGETリクエストもクロスサイトリクエストフォージェリ (CSRF) 保護の対象となりました。これは、サイトの<script>タグのJavaScriptが第三者のサイトから参照されて重要なデータが奪取されないよう保護するためのものです。
つまり、以下を使う機能テストと結合テストは
get :index, format: :js
CSRF保護をトリガーするようになります。以下のように書き換え、
xhr :get, :index, format: :js
XmlHttpRequestを明示的にテストしてください。
自サイトの<script>はクロス参照の出発点として扱われるため、同様にブロックされます。JavaScriptを実際に<script>タグから読み込む場合は、そのアクションでCSRF保護を明示的にスキップしてください。
アプリケーションのプリローダーとしてSpringを使う場合は、以下を行う必要があります。
gem 'spring', group: :development を Gemfileに追加するbundle installを実行してSpringをインストールするbundle exec spring binstub --allを実行してbinstubをSpring化するユーザーが定義したRakeタスクはデフォルトでdevelopment環境で動作するようになります。これらのRakeタスクを他の環境でも実行したい場合はSpring READMEを参考にしてください。
config/secrets.yml新しいsecrets.ymlに秘密鍵を保存したい場合は以下の手順を実行します。
secrets.ymlファイルをconfigフォルダ内に作成し、以下の内容を追加します。
development: secret_key_base: test: secret_key_base: production: secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
secret_token.rbイニシャライザに記載されている既存の secret_key_baseの秘密キーを取り出してSECRET_KEY_BASE環境変数に設定し、Railsアプリケーションをproductionモードで実行するすべてのユーザーが秘密キーの恩恵を受けられるようにします。あるいは、既存のsecret_key_baseをsecret_token.rbイニシャライザからsecrets.ymlのproductionセクションにコピーし、'<%= ENV["SECRET_KEY_BASE"] %>'を置き換えることもできます。
secret_token.rbイニシャライザを削除します
rake secretを実行し、developmentセクションtestセクションに新しい鍵を生成します。
サーバーを再起動します。
テストヘルパーに含まれているActiveRecord::Migration.check_pending!呼び出しは削除できます。このチェックはrequire 'rails/test_help'の際に自動的に行われるようになりました。この呼び出しを削除しなくても悪影響が生じることはありません。
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セッションストアを使う場合、sessionや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メッセージのキーは必ず文字列と比較してください。
Rails 4.1ではJSONの扱いが大きく変更された点が4つあります。
MultiJSONはその役目を終えて end-of-life Railsから削除されました。
アプリケーションがMultiJSONに直接依存している場合、以下のような対応方法があります。
'multi_json'をGemfileに追加する。ただしこのGemは将来使えなくなるかもしれません。
obj.to_jsonとJSON.parse(str)を用いてMultiJSONから乗り換える。
MultiJson.dump と MultiJson.loadをそれぞれJSON.dumpとJSON.loadに単純に置き換えては「いけません」。これらのJSON gem APIは任意のRubyオブジェクトをシリアライズおよびデシリアライズするためのものであり、一般に安全ではありません。
これまでのRailsでは、JSON gemとの互換性に何らかの問題が生じていました。Railsアプリケーション内のJSON.generateとJSON.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>\""
Rails 4.1のJSONエンコーダは、JSON gemを使うように書き直されました。この変更によるアプリケーションへの影響はほとんどありません。ただし、エンコーダが書き直された際に以下の機能がエンコーダから削除されました。
encode_jsonフックのサポートBigDecimalオブジェクトを文字ではなく数字としてエンコードするオプションアプリケーションがこれらの機能に依存している場合は、activesupport-json_encoder gemをGemfileに追加することで以前の状態に戻すことができます。
日時に関連するコンポーネント(Time、DateTime、ActiveSupport::TimeWithZone)を持つオブジェクトに対して#as_jsonを実行すると、デフォルトでミリ秒単位の精度で値が返されるようになりました。ミリ秒より精度の低い従来方式にしておきたい場合は、イニシャライザに以下を設定してください。
ActiveSupport::JSON::Encoding.time_precision = 0
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を参照してください。
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
Rails 4.1からI18nオプションenforce_available_localesがデフォルトでtrueになりました。この設定にすると、I18nに渡されるすべてのロケールは、available_localesリストで宣言されていなければ使えません。
この機能をオフにしてI18nですべての種類のロケールオプションを使えるようにするには、以下のように変更します。
config.i18n.enforce_available_locales = false
enforce_available_localesはセキュリティのために行われていることにご注意ください。つまり、アプリケーションが把握していないロケールを持つユーザー入力が、ロケール情報として使われることのないようにするためのものです。従って、やむを得ない理由がない限りこのオプションはfalseにしないでください。
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!
デフォルトのスコープは、条件をチェインした場合にオーバーライドされなくなりました。
以前のバージョンでは、モデルで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'
以前と同じ動作に戻したい場合は、unscoped、unscope、rewhere、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'
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で送信されるため、セキュリティ上のリスクが生じる可能性があります。
Rails 4.1では、PostgreSQLのjsonカラムとhstoreカラムを、文字列をキーとするRubyのHashに対応付けるようになりました。なお、以前のバージョンではHashWithIndifferentAccessが使われていました。この変更は、Rails 4.1以降ではシンボルでこれらのデータ型にアクセスできなくなるということを意味します。store_accessorsメソッドはjsonカラムやhstoreカラムに依存しているので、同様にシンボルでのアクセスが行えなくなります。今後は常に文字列をキーにするようにしてください。
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 }
Railsアプリケーションのバージョンが3.2より前の場合、まず3.2へのアップグレードを完了してからRails 4.0へのアップグレードを開始してください。
以下の変更は、アプリケーションをRails 4.0にアップグレードするためのものです。
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メソッドを自由に変更できるのであれば、ルーティングを更新してpatchをputの代わりに利用できます。
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ブログの この記事 を参照してください。
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が代表的ですが、最新の仕様変更をすべてサポートしているわけではありません。
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)
Rails 4.0 では vendor/plugins 読み込みのサポートは完全に終了しました。利用するプラグインはすべてgemに展開してGemfileに追加しなければなりません。 理由があってプラグインをgemにしないのであれば、プラグインをlib/my_plugin/*に移動し、適切な初期化の記述をconfig/initializers/my_plugin.rbに書いてください。
config.active_record.identity_mapを削除する必要があるでしょう。コレクション関連付けのdeleteメソッドは、integerやString引数をレコードの他にレコードIDとしても受け付けるようになりました。これによりdestroyメソッドの動作にかなり近くなりました。以前はこのような引数を使うとActiveRecord::AssociationTypeMismatch例外が発生しました。Rails 4.0からは、deleteメソッドを使うと、与えられたIDにマッチするレコードを自動的に探すようになりました。
Rails 4.0では、カラムやテーブルの名前を変更すると、関連するインデックスも自動的にリネームされるようになりました。インデックス名を変更するためだけのマイグレーションは今後不要になりました。
Rails 4.0のserialized_attributesメソッドとattr_readonlyメソッドは、クラスメソッドとしてのみ使う形に変更されました。これらのメソッドをインスタンスメソッドとして利用することは非推奨となったため、行わないでください。たとえばself.serialized_attributesはself.class.serialized_attributesのようにクラスメソッドとしてお使いください。
デフォルトのコーダーを使う場合、シリアル化属性にnilを渡すと、YAML全体にわたって (nil値を渡す代わりに) NULLとしてデータベースに保存されます ("--- \n...\n")。
Rails 4.0ではStrong Parametersの導入に伴い、attr_accessibleとattr_protectedが廃止されました。これらを引き続き使いたい場合は、Protected Attributes gem を導入することでスムーズにアップグレードすることができます。
Protected Attributesを使っていない場合は、whitelist_attributesやmass_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は、従来の実装での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::CategoryとCatalog::Product間のリレーションや、Catalog::CategoryとCatalogProduct間のリレーションも同様に更新する必要があります。Rails 4.0ではActive Resourceがgem化されました。この機能が必要な場合はActive Resource gem をGemfileに追加できます。
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
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を設定しないでください。
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_pageを使いたい場合は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_ifやlink_to_unlessなどでも同様の対応が必要です。
Rails 4.0ではassert_generates、assert_recognizes、assert_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メソッド内で使うことで、作成されるルーティングを制限できます。詳細はRailsのルーティングを参照。
get Rack::Utils.escape('こんにちは'), controller: 'welcome', action: 'index'
上のコードは以下のように変更する必要があります。
get 'こんにちは', controller: 'welcome', action: 'index'
matchを使う場合は、リクエストメソッドの指定が必須となりました。以下に例を示します。# Rails 3.x match '/' => 'root#index' # 上のコードは以下のように変更する必要があります。 match '/' => 'root#index', via: :get # または get '/' => 'root#index'
ActionDispatch::BestStandardsSupportミドルウェアが削除されました。<!DOCTYPE html>は既に https://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がある場合は削除します。
config.action_dispatch.default_headersを設定することでHTTPヘッダーを設定できるようになりました。デフォルト設定は以下のとおりです。config.action_dispatch.default_headers = { 'X-Frame-Options' => 'SAMEORIGIN', 'X-XSS-Protection' => '1; mode=block' }
ただし、アプリケーションが特定のページで<frame>や<iframe>を読み込むことに依存している場合、X-Frame-Optionsを明示的にALLOW-FROM ...またはALLOWALLに設定する必要が生じる可能性があることにご注意ください。
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が非推奨となりました。
Rails 4.0ではERB::Util#json_escapeのエイリアスjが廃止されました。このエイリアスjは既にActionView::Helpers::JavaScriptHelper#escape_javascriptで使われているためです。
Rails 3.xからRails 4.0への移行に伴い、キャッシュ用のメソッドが変更されましたキャッシュの名前空間を変更し、コールドキャッシュ (cold cache) を使って更新してください。
Rails 4.0では複数のディレクトリからのヘルパーの読み込み順が変更されました。以前はすべてのヘルパーをいったん集めてからアルファベット順にソートしていました。Rails 4.0にアップグレードすると、ヘルパーは読み込まれたディレクトリの順序を保持し、ソートは各ディレクトリ内でのみ行われます。helpers_pathパラメータを明示的に利用している場合を除いて、この変更はエンジンからヘルパーを読み込む方法にしか影響しません。ヘルパー読み込みの順序に依存している場合は、アップグレード後に正しいメソッドが使われているかどうかを確認する必要があります。エンジンが読み込まれる順序を変更したい場合は、config.railties_order= メソッドを利用できます。
Active Record ObserverとAction Controller Sweeperはrails-observers gemに切り出されました。これらの機能が必要な場合はrails-observers gemを追加してください。
assets:precompile:primaryおよびassets:precompile:allは削除されました。assets:precompileを代わりにお使いください。config.assets.compressオプションは、たとえば以下のようにconfig.assets.js_compressor に変更する必要があります。config.assets.js_compressor = :uglifier
asset-urlは非推奨となりました。たとえば、asset-url("rails.png", image)はasset-url("rails.png")とする必要があります。Railsアプリケーションのバージョンが3.1よりも古い場合、まず3.1へのアップグレードを完了してからRails 3.2へのアップグレードを開始してください。
以下の変更は、Rails 3.2.xにアップグレードするためのものです。
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
development環境にいくつかの新しい設定を追加する必要があります。
# Active Recordのモデルをマスアサインメントから保護するために例外を発生する config.active_record.mass_assignment_sanitizer = :strict # クエリの実行計画 (クエリプラン) を現在より多く出力する # (SQLite、MySQL、PostgreSQLで動作) config.active_record.auto_explain_threshold_in_seconds = 0.5
mass_assignment_sanitizer設定をconfig/environments/test.rbにも追加する必要があります。
# Active Recordのモデルをマスアサインメントから保護するために例外を発生する config.active_record.mass_assignment_sanitizer = :strict
vendor/plugins はRails 3.2で非推奨となり、Rails 4.0では完全に削除されました。Rails 3.2へのアップグレードでは必須ではありませんが、今のうちにプラグインをgemにエクスポートしてGemfileに追加するのがよいでしょう。理由があってプラグインをgemにしないのであれば、プラグインをlib/my_plugin/*に移動し、適切な初期化の記述をconfig/initializers/my_plugin.rbに書いてください。
:dependent => :restrictオプションはbelongs_toから削除されました。関連付けられたオブジェクトがある場合にこのオブジェクトを削除したくない場合は、:dependent => :destroyを設定し、関連付けられたオブジェクトのdestroyコールバックとの関連付けがあるかどうかを確認してからfalseを返すようにします。
Railsアプリケーションのバージョンが3.0より前の場合、まず3.0へのアップグレードを完了してからRails 3.1へのアップグレードにとりかかってください。
以下の変更は、Rails 3.1.xの最新版であるRails 3.1.12にアップグレードするためのものです。
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'
アセットパイプラインを利用するには、以下の変更が必要です。
config.assets.enabled = true config.assets.version = '1.0'
Railsアプリケーションでリソースのルーティングに/assetsルートを使っている場合、コンフリクトを避けるために以下の変更を加えます。
# '/assets'のデフォルト config.assets.prefix = '/asset-files'
RJSの設定config.action_view.debug_rjs = trueを削除してください。
アセットパイプラインを有効にしている場合は以下の設定を追加します。
# 開発環境ではアセットを圧縮しない config.assets.compress = false # アセットで読み込んだ行を展開する config.assets.debug = true
以下の変更はほとんどがアセットパイプライン用です。詳しくは アセットパイプライン ガイドを参照してください。
# 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
テスト環境に以下を追加することでテストのパフォーマンスが向上します。
# Cache-Controlを使うテストで静的アセットサーバーを構成し、パフォーマンスを向上させる config.public_file_server.enabled = true config.public_file_server.headers = { 'Cache-Control' => 'public, max-age=3600' }
ネストしたハッシュにパラメータを含めたい場合は、このファイルに以下のコンテンツを含めて追加します。新しいアプリケーションではこれがデフォルトになります。
# このファイルを変更後サーバーを必ず再起動してください。 # このファイルには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
何らかの新しいセッションキーを設定するか、すべてのセッションを削除するかのどちらかにする必要があります。
# config/initializers/session_store.rbに以下を設定する AppName::Application.config.session_store :cookie_store, key: 'SOMETHINGNEW'
または
$ bin/rake db:sessions:clear
Railsガイドは GitHub の yasslab/railsguides.jp で管理・公開されております。本ガイドを読んで気になる文章や間違ったコードを見かけたら、気軽に Pull Request を出して頂けると嬉しいです。Pull Request の送り方については GitHub の README をご参照ください。
原著における間違いを見つけたら『Rails のドキュメントに貢献する』を参考にしながらぜひ Rails コミュニティに貢献してみてください 🛠💨✨
本ガイドの品質向上に向けて、皆さまのご協力が得られれば嬉しいです。
Railsガイド運営チーム (@RailsGuidesJP)
Railsガイドは下記の協賛企業から継続的な支援を受けています。支援・協賛にご興味あれば協賛プランからお問い合わせいただけると嬉しいです。