本ガイドでは、アプリケーションで使われているRuby on Railsのバージョンを新しいバージョンにアップグレードする手順を解説します。アップグレードの手順は、Railsのバージョンごとに記載されています。
ActionView::Helpers::UrlHelper#button_to
の振る舞いが変更されたzeitwerk
モードでの実行が必須config.autoloader=
セッターが削除されたActiveSupport::Dependencies
のprivate APIが削除されたconfig.autoload_once_paths
を設定可能になったActionDispatch::Request#content_type
が Content-Typeヘッダーをそのまま返すようになったActiveSupport::Digest
で用いられるメッセージダイジェストクラスがSHA256に変更ActiveSupport::Cache
の新しいシリアライズフォーマット:vips
に変更Rails.application.config_for
の戻り値をStringキーでアクセスするサポートが終了したrespond_to#any
を使う場合のレスポンスのContent-TypeヘッダーについてActiveSupport::Callbacks#halted_callback_hook
に第2引数を渡せるようになったhelper
のクラスメソッドがString#constantize
を使うようになったActiveModel::Error
クラスが追加されたthrow(:abort)
でコールバックチェインを停止するmysql
データベースアダプタのサポートを終了bin/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.yml
return
を利用できなくなるActiveSupport::Callbacks
では明示的にブロックを利用すること既存のアプリケーションをアップグレードする前に、アップグレードする理由を明確にしておく必要があります。「新しいバージョンのどの機能か必要か」「既存コードのサポートがどのぐらい困難になるか」「アップグレードに割り当てられる時間と人員スキルはどのぐらいか」など、いくつもの要素を調整しなければなりません。
アップグレード後にアプリケーションが正常に動作していることを確認するには、良いテストカバレッジをアップグレード前に準備しておくのがベストです。アプリケーションを一度に検査できる自動テストがないと、変更点をすべて手動で確認するのに膨大な時間がかかってしまいます。Railsのようなアプリケーションの場合、これはアプリケーションのあらゆる機能を1つ残らず確認しなければならないということです。アップグレードを実施する「前に」、テストカバレッジが揃っていることを確認しておいてください。
Railsでは、一般にRubyの最新版がリリースされると最新版のRubyに近い状態に合わせます。
RubyのアップグレードとRailsのアップグレードは別々に行うのがよい方法です。最初にRubyを可能な限り最新版にアップグレードし、それからRailsをアップグレードします。
Railsのバージョンを変更する場合、マイナーバージョンを1つずつゆっくりと上げながら、その都度表示される非推奨機能の警告メッセージを上手に利用するのがベストです。言い換えると、アップグレードを急ぐあまりバージョンをスキップするべきではありません。Railsのバージョン番号は「メジャー番号.マイナー番号.パッチ番号」の形式を取ります。メジャーバージョンやマイナーバージョンの変更では、public APIの変更によるエラーがアプリケーションで発生する可能性があります。パッチバージョンはバグ修正のみが含まれ、public API変更は含まれません。
アップグレードは以下の手順で行います。
上の手順を繰り返して、最終的にRailsを目的のバージョンにアップグレードします。
リリース済みのRailsバージョンのリストはここで確認できます。
Railsのバージョン間を移動するには以下のようにします。
Gemfile
ファイル内のRailsバージョン番号を変更し、bundle update
を実行する。package.json
ファイル内のRails JavaScriptパッケージのバージョンを変更する。Webpackerで動かす場合はyarn install
を実行する。リリースされたすべてのRails gemリストについてはこちらを参照してください。
Rails ではapp:update
というコマンドが提供されています。Gemfile
に記載されているRailsのバージョンを更新後、このコマンドを実行することで、新しいバージョンでのファイル作成や既存ファイルの変更を対話形式で行うことができます。
$ bin/rails app:update exist config conflict config/application.rb Overwrite /myapp/config/application.rb? (enter "h" for help) [Ynaqdh] force config/application.rb create config/initializers/new_framework_defaults_7_0.rb ...
予期しなかった変更が発生した場合は、必ず差分を十分チェックしてください。
新しいバージョンのRailsでは、前のバージョンとデフォルト設定が異なるものがあります。しかし上述の手順に従うことで、アプリケーションが引き続き従来バージョンのRailsのデフォルト設定で実行されます(config/application.rb
のconfig.load_defaults
の値がまだ変更されていないため)。
app:update
タスクでは、アプリケーションを新しいデフォルト設定に1つずつアップグレードできるように、config/initializers/new_framework_defaults_X.Y.rb
ファイルが作成されます(ファイル名にはRailsのバージョンが含まれます)。このファイル内のコメントを解除して、新しいデフォルト設定を有効にする必要があります。この作業は、数回のデプロイに分けて段階的に実行できます。アプリケーションを新しいデフォルト設定で動かせる準備が整ったら、このファイルを削除してconfig.load_defaults
の値を反転できます。
Rails 7.0で行われた変更について詳しくは、7.0リリースノートを参照してください。
ActionView::Helpers::UrlHelper#button_to
の振る舞いが変更されたRails 7.0以降のbutton_to
は、ボタンURLをビルドするのに使われるActive Recordオブジェクトが永続化されている場合は、patch
HTTP verbを用いるform
タグをレンダリングします。現在の振る舞いを維持するには、以下のように明示的にmethod:
オプションを渡します。
-button_to("Do a POST", [:my_custom_post_action_on_workshop, Workshop.find(1)]) +button_to("Do a POST", [:my_custom_post_action_on_workshop, Workshop.find(1)], method: :post)
または、以下のようにURLをビルドするヘルパーを使います。
-button_to("Do a POST", [:my_custom_post_action_on_workshop, Workshop.find(1)]) +button_to("Do a POST", my_custom_post_action_on_workshop_workshop_path(Workshop.find(1)))
アプリケーションでspring gemを使っている場合は、spring gemのバージョンを3.0.0以上にアップグレードする必要があります。そうしないと以下のエラーが発生します。
undefined method `mechanism=' for ActiveSupport::Dependencies:Module
また、config/environments/test.rb
でconfig.cache_classes
設定を必ずfalse
にしてください。
rails
gemはsprockets-rails
に依存しなくなりました。アプリケーションで引き続きSprocketsを使う必要がある場合は、Gemfileにsprockets-rails
を追加してください。
gem "sprockets-rails"
zeitwerk
モードでの実行が必須classic
モードで動作しているアプリケーションは、zeitwerk
モードに切り替えなければなりません。詳しくはクラシックオートローダーからZeitwerkへの移行ガイドを参照してください。
config.autoloader=
セッターが削除されたRails 7では、オートロードのモードを指定するconfig.autoloader=
設定そのものがなくなりました。何らかの理由で:zeitwerk
に設定していた場合は、その設定行を削除してください。
ActiveSupport::Dependencies
のprivate APIが削除されたActiveSupport::Dependencies
のprivate APIが削除されました。hook!
、unhook!
、depend_on
、require_or_load
、mechanism
など多数のメソッドが削除されています。
注意点をいくつか示します。
ActiveSupport::Dependencies.constantize
またはActiveSupport::Dependencies.safe_constantize
を使っている場合は、String#constantize
またはString#safe_constantize
に変更してください。ActiveSupport::Dependencies.constantize("User") # 今後は利用不可 "User".constantize # 👍
ActiveSupport::Dependencies.mechanism
やそのリーダーやライターを使っている場合は、config.cache_classes
のアクセスで置き換える必要があります。
オートローダーの動作をトレースしたい場合、ActiveSupport::Dependencies.verbose=
は利用できなくなりました。config/application.rb
でRails.autoloaders.log!
をスローしてください。
ActiveSupport::Dependencies::Reference
やActiveSupport::Dependencies::Blamable
などの補助的なクラスやモジュールも削除されました。
Rails 6.0以降では、アプリケーションの初期化中に、再読み込み可能な定数をto_prepare
ブロックの外でオートロードすると、それらの定数がアンロードされて以下の警告が出力されます。
DEPRECATION WARNING: Initialization autoloaded the constant .... Being able to do this is deprecated. Autoloading during initialization is going to be an error condition in future versions of Rails. ...
この警告が引き続きログに出力される場合は、アプリケーション起動時の自動読み込みでアプリケーション起動時のオートロードについての記述を参照してください。これに対応しないと、Rails 7でNameError
が出力されます。
config.autoload_once_paths
を設定可能になったconfig.autoload_once_paths
は、config/application.rb
で定義されるApplicationクラスの本体、またはconfig/environments/*
の環境向け設定で設定可能です。
エンジンも同様に、エンジンクラスのクラス本体内にあるコレクションや、環境向けの設定内にあるコレクションを設定可能です。
コレクションは以後frozenになり、これらのパスからオートロードできるようになります。特に、これらのパスから初期化中にオートロードできるようになります。これらのパスは、Rails.autoloaders.once
オートローダーで管理されます。このオートローダーはリロードを行わず、オートロードやeager loadingのみを行います。
環境設定が完了した後でこの設定を行ったときにFrozenError
が発生する場合は、コードの置き場所を移動してください。
ActionDispatch::Request#content_type
が Content-Typeヘッダーをそのまま返すようになった従来は、ActionDispatch::Request#content_type
が返す値にcharsetパートが含まれて「いませんでした」。
この振る舞いが変更され、charsetパートを含むContent-Typeヘッダーをそのまま返すようになりました。
MIMEタイプだけが欲しい場合は、代わりにActionDispatch::Request#media_type
をお使いください。
変更前:
request = ActionDispatch::Request.new("CONTENT_TYPE" => "text/csv; header=present; charset=utf-16", "REQUEST_METHOD" => "GET") request.content_type #=> "text/csv"
変更後:
request = ActionDispatch::Request.new("Content-Type" => "text/csv; header=present; charset=utf-16", "REQUEST_METHOD" => "GET") request.content_type #=> "text/csv; header=present; charset=utf-16" request.media_type #=> "text/csv"
キージェネレータで用いられるデフォルトのダイジェストクラスが、SHA1からSHA256に変更されました。 その結果、Railsで生成されるあらゆる暗号化メッセージがこの影響を受けるようになり、暗号化および署名済みcookieも同様に影響を受けます。
古いダイジェストクラスを用いてメッセージを読めるようにするには、ローテータの登録が必要です。
以下は、暗号化cookie向けのローテータの設定例です。
# config/initializers/cookie_rotator.rb Rails.application.config.after_initialize do Rails.application.config.action_dispatch.cookies_rotations.tap do |cookies| authenticated_encrypted_cookie_salt = Rails.application.config.action_dispatch.authenticated_encrypted_cookie_salt signed_cookie_salt = Rails.application.config.action_dispatch.signed_cookie_salt secret_key_base = Rails.application.secret_key_base key_generator = ActiveSupport::KeyGenerator.new( secret_key_base, iterations: 1000, hash_digest_class: OpenSSL::Digest::SHA1 ) key_len = ActiveSupport::MessageEncryptor.key_len old_encrypted_secret = key_generator.generate_key(authenticated_encrypted_cookie_salt, key_len) old_signed_secret = key_generator.generate_key(signed_cookie_salt) cookies.rotate :encrypted, old_encrypted_secret cookies.rotate :signed, old_signed_secret end end
ActiveSupport::Digest
で用いられるメッセージダイジェストクラスがSHA256に変更ActiveSupport::Digest
で用いられるデフォルトのダイジェストクラスがSHA1からSHA256に変更されます。
その結果、Etagなどの変更やキャッシュキーにも影響します。
これらのキーを変更すると、キャッシュのヒット率が低下する可能性があるので、新しいハッシュにアップグレードする際は慎重に進めるようご注意ください。
ActiveSupport::Cache
の新しいシリアライズフォーマットより高速かつコンパクトな新しいシリアライズフォーマットが導入されました。
これを有効にするには、以下のようにconfig.active_support.cache_format_version = 7.0
を設定する必要があります。
# config/application.rb config.load_defaults 6.1 config.active_support.cache_format_version = 7.0
または以下のようにシンプルに設定します。
# config/application.rb config.load_defaults 7.0
ただし、Rails 6.1アプリケーションはこの新しいシリアライズフォーマットを読み取れないので、シームレスにアップグレードするには、まずRails 7.0へのアップグレードをconfig.active_support.cache_format_version = 6.1
でデプロイし、Railsプロセスがすべて更新されたことを確かめてからconfig.active_support.cache_format_version = 7.0
を設定する必要があります。
Rails 7.0は新旧両方のフォーマットを読み取れるので、アップグレード中にキャッシュが無効になることはありません。
動画のプレビュー画像生成で、FFmpegの場面転換検出機能を用いて従来よりも意味のあるプレビュー画像を生成するようになりました。従来は動画の冒頭フレームが使われたため、黒画面からフェードインして開始される動画で問題が生じました。この変更にはFFmpeg v3.4以降が必要です。
:vips
に変更新規アプリの画像変換では、従来のImageMagickに代えてlibvipsが使われるようになります。これにより、バリアント(サムネイルなどで用いられるサイズ違いの画像)の生成時間が短縮されるとともにCPUやメモリの使用量も削減され、Active Storageで画像を配信するアプリのレスポンスが向上します。
:mini_magick
オプションは非推奨化されていませんので、引き続き問題なく利用できます。
既存のアプリをlibvipsに移行するには、以下を設定します。
Rails.application.config.active_storage.variant_processor = :vips
続いて、既存の画像変換コードをimage_processing
マクロに変更し、さらにImageMagickのオプションをlibvipsのオプションに置き換える必要があります。
resize
をresize_to_limit
に置き換える- variant(resize: "100x") + variant(resize_to_limit: [100, nil])
上の置き換えを行わないと、vipsに切り替えたときにno implicit conversion to float from string
エラーが表示されます。
crop
で配列を使うよう変更する- variant(crop: "1920x1080+0+0") + variant(crop: [0, 0, 1920, 1080])
上の置き換えを行わないと、vipsに移行したときにunable to call crop: you supplied 2 arguments, but operation needs 5
エラーが表示されます。
crop
の値を固定するvipsのcrop
は、ImageMagickよりも厳密です。
x
やy
が負の値の場合はcrop
されない。例: [-10, -10, 100, 100]
位置(x
またはy
)とcrop
のサイズ(width
、height
)が画像サイズを上回る場合はcrop
されない。例: 125x125の画像に対して[50, 50, 100, 100]
でcrop
する。
上を守らない場合、vipsに移行したときにextract_area: bad extract area
エラーが表示されます。
resize_and_pad
の背景色を調整するvipsのresize_and_pad
では、デフォルトバックグラウンド色にImageMagickの白ではなく黒が使われます。これは以下のようにbackground:
オプションで修正できます。
- variant(resize_and_pad: [300, 300]) + variant(resize_and_pad: [300, 300, background: [255]])
vipsでは、バリアントを処理中にEXIF値を用いて画像を自動回転します。ユーザーがアップロードした写真の回転値を保存してImageMagickで回転するのであれば、以下のようにこの機能を止める必要があります。
- variant(format: :jpg, rotate: rotation_value) + variant(format: :jpg)
monochrome
をcolourspace
に置き換える。vipsでは、モノクロ画像を作成するオプションを以下のように変更する必要があります。
- variant(monochrome: true) + variant(colourspace: "b-w")
JPEGの場合。
- variant(strip: true, quality: 80, interlace: "JPEG", sampling_factor: "4:2:0", colorspace: "sRGB") + variant(saver: { strip: true, quality: 80, interlace: true })
PNGの場合。
- variant(strip: true, quality: 75) + variant(saver: { strip: true, compression: 9 })
WEBPの場合。
- variant(strip: true, quality: 75, define: { webp: { lossless: false, alpha_quality: 85, thread_level: 1 } }) + variant(saver: { strip: true, quality: 75, lossless: false, alpha_q: 85, reduction_effort: 6, smart_subsample: true })
GIFの場合。
- variant(layers: "Optimize") + variant(saver: { optimize_gif_frames: true, optimize_gif_transparency: true })
Active Storageは、実行されなければならない変換のリストを画像URLにエンコードします。 アプリケーションがこれらの画像URLをキャッシュしていると、新しいコードをproduction環境にデプロイした後で画像が破損します。 このため、影響を受けるキャッシュキーを手動で無効にしなければなりません。
たとえば、以下のようなビューがあるとします。
<% @products.each do |product| %> <% cache product do %> <%= image_tag product.cover_photo.variant(resize: "200x") %> <% end %> <% end %>
このキャッシュを無効にするには、product
を以下のように変更するか、キャッシュキーを変更します。
<% @products.each do |product| %> <% cache ["v2", product] do %> <%= image_tag product.cover_photo.variant(resize_to_limit: [200, nil]) %> <% end %> <% end %>
Rails 7.0では、いくつかのカラムタイプのデフォルト値が変更されました。6.1から7.0にアップグレードしたアプリケーションが現在のスキーマを読み込むときに、7.0の新しいデフォルト値が使われるのを避けるため、Railsはスキーマダンプにフレームワークのバージョンを含めるようになりました。
Rails 7.0で初めてスキーマを読み込むときは、その前にrails app:update
を実行して、スキーマのバージョンがスキーマダンプに含まれていることを確認してください。
スキーマファイルは以下のような感じになります。
# This file is auto-generated from the current state of the database. Instead # of editing this file, please use the migrations feature of Active Record to # incrementally modify your database, and then regenerate this schema definition. # # This file is the source Rails uses to define your schema when running `bin/rails # db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to # be faster and is potentially less error prone than running all of your # migrations from scratch. Old migrations may fail to apply correctly if those # migrations use external dependencies or application code. # # It's strongly recommended that you check this file into your version control system. ActiveRecord::Schema[6.1].define(version: 2022_01_28_123512) do
Rails 7.0で初めてスキーマをダンプすると、そのファイルでカラム情報などさまざまな変更が行われていることがわかります。必ず新しいスキーマファイルの内容を確認してから、リポジトリにコミットすることを忘れないようにしましょう。
Rails 6.1の変更点について詳しくはリリースノートを参照してください。
Rails.application.config_for
の戻り値をStringキーでアクセスするサポートが終了した以下のような設定ファイルがあるとします。
# config/example.yml development: options: key: value
Rails.application.config_for(:example).options
従来は、Stringキーで値にアクセス可能なハッシュを1つ返しました。この機能は6.0で非推奨化され、6.1で削除されました。
従来どおりStringキーを用いて値にアクセスしたい場合は、config_for
の戻り値でwith_indifferent_access
を呼び出せます。
Rails.application.config_for(:example).with_indifferent_access.dig('options', 'key')
respond_to#any
を使う場合のレスポンスのContent-Typeヘッダーについてレスポンスで返されるContent-Typeヘッダーは、Rails 6.0で返されるものと異なる可能性があります。特にアプリケーションでrespond_to { |format| format.any }
を使っている場合、Content-Typeヘッダーはリクエストのフォーマットではなく、渡されたブロックを元にするようになりました。
以下の例をご覧ください。
def my_action respond_to do |format| format.any { render(json: { foo: 'bar' }) } end end
get('my_action.csv')
従来の振る舞いではレスポンスのContent-Typeでtext/csv
を返していましたが、実際にはJSONレスポンスをレンダリングしているので正しくありません。現在の振る舞いではレスポンスのContent-Typeでapplication/json
を正しく返すようになりました。
アプリケーションが従来の正しくない振る舞いに依存している場合は、以下のようにアクションで受け取るフォーマットを明示的に指定してください。
format.any(:xml, :json) { render request.format.to_sym => @people }
ActiveSupport::Callbacks#halted_callback_hook
に第2引数を渡せるようになったActive Supportは、コールバックのチェーンがhalt(停止)したときのhalted_callback_hook
をオーバーライドできます。このメソッドに、halt中のコールバック名を第2引数として渡せるようになりました。このメソッドをオーバーライドするクラスがある場合は、引数を2つ受け取れるようにしてください。なおパフォーマンス上の理由のため、この破壊的変更は非推奨化を経ていません。
以下の例をご覧ください。
class Book < ApplicationRecord before_save { throw(:abort) } before_create { throw(:abort) } def halted_callback_hook(filter, callback_name) # => このメソッドが1個ではなく2個の引数を取れるようになった Rails.logger.info("Book couldn't be #{callback_name}d") end end
helper
のクラスメソッドがString#constantize
を使うようになった概念について説明します。
helper "foo/bar"
Rails 6.1より前は、上のコードから以下の結果が得られました。
require_dependency "foo/bar_helper" module_name = "foo/bar_helper".camelize module_name.constantize
Rail 6.1では以下のような結果になります。
prefix = "foo/bar".camelize "#{prefix}Helper".constantize
この変更は、多くのアプリケーションで後方互換性が保たれているので、これに該当する場合は対応不要です。
ただし技術的には、autoloadパス上にない$LOAD_PATH
内のディレクトリを指すようコントローラがhelpers_path
を設定することも可能でしたが、今後このようなユースケースはすぐ使える形ではサポートされません。ヘルパーモジュールがオートロード可能でない場合は、helper
を呼び出す前にアプリケーションが明示的に読み込んでおく責任があります。
(訳注)詳しくはRemove `require_dependency` usage in `helper` [Closes #37632] · rails/rails@5b28a0eもどうぞ。helper
での読み込みにrequire_dependency
が使われなくなったことによる変更です。
ActionDispatch::SSL
でGETやHEAD以外のリクエストをHTTPからHTTPSにリダイレクトする場合のデフォルトHTTPステータスコードが、RFC7538の定義に従って308
に変更されました。
Active Storageでvariantを処理する場合、従来のようにmini_magick
を直接利用するのではなく、image_processing gemのバンドルが必須になりました。image_processingの背後ではデフォルトでmini_magick
が使われるので、不要になった明示的なcombine_options
を必ず削除してください。
できれば、image_processing
のresize
マクロの直接呼び出しも変更しておくことをおすすめします(変更することでリサイズ後のサムネイルもシャープになります)。
video.preview(resize: "100x100") video.preview(resize: "100x100>") video.preview(resize: "100x100^")
たとえば、上のコードはそれぞれ以下のように変更できます。
video.preview(resize_to_fit: [100, 100]) video.preview(resize_to_limit: [100, 100]) video.preview(resize_to_fill: [100, 100])
ActiveModel::Error
クラスが追加されたエラーが新しく ActiveModel::Error
クラスのインスタンスになり、APIの変更もあわせて行われました。これらの変更によって、新しくエラーが発生する、または Rails 7.0 で廃止されるため非推奨の警告を出力する場合があります。
この変更とAPIの詳細についてはPRを参照してください。
Rails 6.0の変更点について詳しくはリリースノートを参照してください。
WebpackerはRails 6におけるデフォルトのJavaScriptコンパイラですが、アプリケーションを以前のバージョンからアップグレードした場合は自動的には有効になりません。
Webpackerを使いたい場合は、以下をGemfileに追記し、bin/rails webpacker:install
コマンドを実行してインストールしてください。
gem "webpacker"
$ bin/rails webpacker:install
コントローラのforce_ssl
メソッドは非推奨化され、Rails 6.1で削除される予定です。config.force_ssl
設定を有効にしてアプリ全体でHTTPS接続を強制することをおすすめします。特定のエンドポイントのみをリダイレクトしないようにする必要がある場合は、config.ssl_options
で振る舞いを変更できます。
これにより、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
を設定してください。
@rails
スコープに移動これまで「actioncable
」「activestorage
」「rails-ujs
」パッケージのいずれかをnpmまたはyarn経由で読み込んでいた場合は、これらを6.0.0
にアップグレードする前にそれらの依存関係の名前を以下のように更新しなければなりません。
actioncable → @rails/actioncable activestorage → @rails/activestorage rails-ujs → @rails/ujs
Action Cable JavaScriptパッケージがCoffeeScriptからES2015に置き換えられ、ソースコードをnpmディストリビューションでパブリッシュできるようになりました。
今回のリリースでは、Action Cable JavaScript APIの選択可能な部分に若干のbreaking changesが生じます。
WebSocketアダプタやロガーアダプタの設定が、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で管理します。
以前のバージョンのRailsのデフォルトを使っている場合は、以下の方法でzeitwerkを有効にできます。
# config/application.rb config.autoloader = :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 Hold on, I am eager loading the application. All is good!
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
concerns
について以下のような標準的な構造は、オートロードもeager loadも可能です。
app/models app/models/concerns
上は、(オートロードパスに属するので)app/models/concerns
がrootディレクトリであると仮定され、名前空間としては無視されます。したがって、app/models/concerns/foo.rb
はConcerns::Foo
ではなくFoo
と定義すべきです。
Concerns::
名前空間は、classic
モードのオートローダーでは実装の副作用によって動作していましたが、実際は意図した動作ではありませんでした。Concerns::
を使っているアプリケーションがzeitwerk
モードで動くようにするには、こうしたクラスやモジュールをリネームする必要があります。
app
がある場合プロジェクトによっては、API::Base
を定義するためにapp/api/base.rb
のようなものが欲しい場合があります。classic
モードではこれを行うためにオートロードパスにapp
を追加します。Railsはapp
の全サブディレクトリをオートロードに自動的に追加するので、ネストしたルートディレクトリがある状況がもう1つ存在することになり、セットアップが機能しなくなります。この原則は上述のconcerns
と同様です。
そうした構造を維持したい場合は、イニシャライザで以下のようにサブディレクトリをオートロードパスから削除する必要があります。
ActiveSupport::Dependencies.autoload_paths.delete("#{Rails.root}/app/api")
あるファイルの中で名前空間が1つ定義されているとします(ここではHotel
)。
app/models/hotel.rb # Hotelが定義される app/models/hotel/pricing.rb # 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
config.add_autoload_paths_to_load_path
は、後方互換性のためデフォルトでtrue
になっていますが、これをfalse
にすると$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.highlights.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 7.0で非推奨化され、Rails 7.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を返します。
redirect_to :back
サポートが削除されたRails 5.0で非推奨化されたredirect_to :back
は、Rails 5.1で完全に削除されました。
今後は代わりにredirect_back
をお使いください。redirect_back
は、HTTP_REFERER
が見つからない場合に使われるfallback_location
オプションも受け取る点にご注意ください。
redirect_back(fallback_location: root_path)
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
しなくても問題なく利用でき、従来と同様にオートロードされます。
トップレベルより下で、実行時にのみ有効にする定数(通常のメソッド本体など)を定義した場合も、起動時にeager loadingされるので問題なく利用できます。
ほとんどのアプリケーションでは、この変更に関して特別な対応は不要です。ごくまれに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
をお使いください。
bin/rails
を使うことRails 5では、rakeに代わってbin/rails
でタスクやテストを実行できるようになりました。原則として、多くのタスクやテストはrakeでも引き続き実行できますが、一部のタスクやテストは完全にbin/rails
に移行しました。
今後テストの実行にはbin/rails test
をお使いください。
rake dev:cache
はbin/rails dev:cache
に変更されました。
アプリケーションのルートディレクトリの下でbin/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
これはデフォルトですべてのモデルに対してグローバルに設定されますが、モデルごとに設定をオーバーライドすることもできます。これは、モデルを移行してデフォルトで必要な関連付けをすべてのモデルに持たせるのに便利です。
class Book < ApplicationRecord # モデルがデフォルトで必要な関連付けを持つ準備ができていない場合の設定 self.belongs_to_required_by_default = false belongs_to(:author) end class Car < ApplicationRecord # モデルがデフォルトで必要な関連付けを持つ準備ができた後の設定 self.belongs_to_required_by_default = true belongs_to(:pilot) end
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
値を渡す(JSON
コーダーを使う場合の"null"
など)のではなく、データベースにNULL
として保存されるようになりました。
Rails 5のproduction環境では、デフォルトのログレベルが:info
から:debug
に変更される予定です。現在のログレベルを変更したくない場合はproduction.rb
に以下の行を追加してください。
# `:info`を指定すると現在のデフォルト設定が使われ、 # `:debug`を指定すると今後のデフォルト設定が使われる config.log_level = :info
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
アプリケーションでHTMLの断片をサニタイズする方法に新しい選択肢が追加され、従来の伝統的なHTMLスキャンによるサニタイズは公式に非推奨化されました。現在推奨される方法はrails-html-sanitizer
です。
これにより、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保護これを行わないと、「なぜかテストがパスしない」「<script>
ウィジェットがおかしい!」などという結果になりかねません。
JavaScriptレスポンスを伴うGETリクエストもCSRF(クロスサイトリクエストフォージェリ)保護の対象となりました。これは、サイトの<script>
タグのJavaScriptコードが第三者のサイトから参照されて重要なデータが奪取されないよう保護するためのものです。
つまり、以下を使う機能テストや結合テストではCSRF保護が発動します。
get :index, format: :js
XmlHttpRequest
を明示的にテストするには、以下のように書き換えます。
xhr :get, :index, format: :js
自サイトの<script>
はクロスオリジンとして扱われるため、同様にブロックされます。JavaScriptを実際に<script>
タグから読み込む場合は、そのアクションでCSRF保護を明示的にスキップしなければなりません。
アプリケーションのプリローダーとしてspring gemを使う場合は、以下を行う必要があります。
gem 'spring', group: :development
を Gemfile
に追加するbundle install
を実行してspringをインストールするbundle exec spring binstub
を実行してspringのbinstubを生成するユーザーが定義した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_token.rb
イニシャライザにある既存のsecret_key_base
をsecrets.yml
のproductionセクションにコピーし、'<%= ENV["SECRET_KEY_BASE"] %>'を置き換えることもできます。
secret_token.rb
イニシャライザを削除する。
development
セクションとtest
セクションで使う新しい鍵をrake secret
で生成する。
サーバーを再起動する。
テストヘルパーに含まれている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
でシリアライズされた既存のcookieを、新しいJSON
ベースのフォーマットに透過的に移行できます。
:json
または:hybrid
シリアライザを使う場合、一部のRubyオブジェクトがJSONとしてシリアライズされない可能性があることにご注意ください。たとえば、Date
オブジェクトやTime
オブジェクトは文字列としてシリアライズされ、Hash
のキーは文字列に変換されます。
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には文字列や数字などの単純なデータだけを保存することをおすすめします。cookieに複雑なオブジェクトを保存しなければならない場合は、以後のリクエストでcookieから値を読み出すときに自分で変換する必要があります。
これは、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はその役目を終えてRailsから削除されました(#10576)。
アプリケーションが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
irb> FooBar.new.to_json => "{\"foo\":\"bar\"}" irb> 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
など)も含まれます。
詳しくは#13271を参照してください。
Rails 4.1では、各フィクスチャのERBは独立したコンテキストで評価されます。このため、あるフィクスチャで定義されたヘルパーメソッドは他のフィクスチャでは利用できません。
ヘルパーメソッドを複数のフィクスチャで共用するには、test_helper.rb
で定義したモジュールを以下のように新しく導入されたActiveRecord::FixtureSet.context_class
でinclude
する必要があります。
module FixtureFileHelpers def file_sha(path) OpenSSL::Digest::SHA256.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
オプションが導入されました。以下のようにContent-Typeヘッダーを指定できるため、文字列ベースのコンテンツ表示にはこれらのオプションの利用が推奨されます。
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
の代わりに利用できます。
resources :users do patch :update_name, on: :member end
Rails 4でPUT
リクエストを/users/:id
に送信すると、従来と同様update
にルーティングされます。このため、実際のPUTリクエストを受け取るAPIは今後も利用できます。この場合、PATCH
リクエストも/users/:id
経由でupdate
アクションにルーティングされます。
このアクションがパブリックAPIで使われており、HTTPメソッドを自由に変更できないのであれば、フォームを更新してPUT
を代わりに使えます。
<%= form_for [ :update_name, @user ], method: :put do |f| %>
PATCHおよびこの変更が行われた理由について詳しくは、Railsブログのこの記事を参照してください。
JSON Patchは、PATCH
verbの正誤表で指摘されている「PATCH
では異なるメディアタイプを使う必要がある」に該当するものの1つです。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のGemfile
からassets
グループが削除されました。アップグレード時にはこの記述を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
に書いてください。
関連付けに関する若干の不整合のため、Rails 4.0ではActive Recordからidentity mapが削除されました。アプリケーションでこの機能を手動で有効にしたい場合は、今や無効になった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
値を渡す("--- \n...\n"
)のではなく、NULL
としてデータベースに保存されます。
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 }
Rails 4.0ではActiveRecord::Fixtures
が非推奨となりました。今後はActiveRecord::FixtureSet
をお使いください。
Rails 4.0ではActiveRecord::TestCase
が非推奨となりました。今後はActiveSupport::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
Rails 4.0からActiveSupport::KeyGenerator
が導入され、署名付きcookieの生成や照合などに使われるようになりました。Rails 3.xで生成された既存の署名付きcookieは、既存の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
で署名されたcookieにはRails 3.xのcookieとの後方互換性がないためです。他のアップグレードが完全に完了するまでは、既存のsecret_token
をそのままにしてsecret_key_base
を設定せず、非推奨警告を無視する方法も可能です。
外部アプリケーションやJavaScriptからRailsアプリケーションの署名付きセッションcookie(または一般の署名付きcookie)を読み出せる必要がある場合は、これらの問題を切り離すまではsecret_key_base
を設定しないでください。
Rails 4.0では、secret_key_base
が設定されているとcookieベースのセッションの内容が暗号化されます。Rails 3.xではcookieベースのセッションを暗号化なしで署名していました。署名付きcookieは、そのRailsアプリケーションで生成されたことが確認でき、不正が防止されるという意味では安全ですが、セッションの内容はエンドユーザーから見えてしまいます。内容を暗号化することで懸念を取り除けるようになり、パフォーマンスもさほど低下しません。
セッションcookieを暗号化する方法について詳しくは#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
属性をお使いください(例: data: { confirm: 'Are you sure?' }
)。link_to_if
やlink_to_unless
などでも同様の対応が必要です。
Rails 4.0ではassert_generates
、assert_recognizes
、assert_routing
の動作が変更されました。これらのアサーションはActionController::RoutingError
の代わりにAssertion
をraiseします。
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のルーティングを参照してください。
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>
は既に 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
がある場合は削除してください。
Rails 4.0では、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
のような低レベルの例外の代わりにこの例外をrescueできます。
Rails 4.0では、URLプレフィックスで指定されたアプリケーションにエンジンがマウントされている場合にSCRIPT_NAME
が正しくネストするようになりました。今後はURLプレフィックスの上書きを回避するためにdefault_url_options[:script_name]
を設定する必要はありません。
Rails 4.0ではActionController::Integration
が非推奨となりました。今後はActionDispatch::Integration
をお使いください。
Rails 4.0ではActionController::IntegrationTest
は非推奨となりました。今後はActionDispatch::IntegrationTest
をお使いください。
Rails 4.0ではActionController::PerformanceTest
が非推奨となりました。今後はActionDispatch::PerformanceTest
をお使いください。
Rails 4.0ではActionController::AbstractRequest
が非推奨となりました。今後はActionDispatch::Request
をお使いください。
Rails 4.0ではActionController::Request
が非推奨となりました。今後はActionDispatch::Request
をお使いください。
Rails 4.0ではActionController::AbstractResponse
が非推奨となりました。今後はActionDispatch::Response
をお使いください。
Rails 4.0ではActionController::Response
が非推奨となりました。今後はActionDispatch::Response
をお使いください。
Rails 4.0ではActionController::Routing
が非推奨となりました。今後はActionDispatch::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
に引数を2つ渡すことは非推奨となりました。たとえば、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
を削除してください。
アセットパイプラインを有効にしている場合は以下の設定を追加します。
# development環境ではアセットを圧縮しない 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とセキュアcookieを使う # 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
:cache
オプションと:concat
オプションは廃止されました。ビューからこれらのオプションを削除してください。Railsガイドは GitHub の yasslab/railsguides.jp で管理・公開されております。本ガイドを読んで気になる文章や間違ったコードを見かけたら、気軽に Pull Request を出して頂けると嬉しいです。Pull Request の送り方については GitHub の README をご参照ください。
原著における間違いを見つけたら『Rails のドキュメントに貢献する』を参考にしながらぜひ Rails コミュニティに貢献してみてください 🛠💨✨
本ガイドの品質向上に向けて、皆さまのご協力が得られれば嬉しいです。
Railsガイド運営チーム (@RailsGuidesJP)
Railsガイドは下記の協賛企業から継続的な支援を受けています。支援・協賛にご興味あれば協賛プランからお問い合わせいただけると嬉しいです。