1 一般的なアドバイス
言うまでもないことですが、既存のアプリケーションをアップグレードする際には、何のためにアップグレードするのかをはっきりさせておく必要があります。新しいバージョンのうちどの機能が必要になるのか、既存のコードのサポートがどのぐらい困難になるのか、アップグレードに必要な時間とスキルはどれほど必要かなど、いくつもの要素を調整しなければなりません。
1.1 テスティングのカバレッジ
アップグレード後にアプリケーションが正常に動作していることを確認する方法としては、良いテストカバレッジをアップグレード前に準備しておくのが最善です。アプリケーションを一気に検査する自動テストがないと、変更点をすべて手動で確認しなければならず膨大な時間がかかってしまいます。Railsのようなアプリケーションの場合、これはアプリケーションのあらゆる機能を一つ残らず確認しなければならないということです。アップグレードの実施は、テストカバレッジをきちんと準備してから行なうよう、お願いいたします。
1.2 Rubyのバージョン
Railsは、そのバージョンがリリースされた時点で最新のバージョンのRubyに依存しています。
- Rails 3以上では、Ruby 1.8.7以降が必須です。これより古いRubyのサポートは公式に停止しています。できるだけ早くアップグレードをお願いします。
- Rails 3.2.xはRuby 1.8.7の最終ブランチです。
- Rails 4ではRuby 2.0が推奨されます。Ruby 1.9.3以上が必須です。
Ruby 1.8.7 p248およびp249にはRailsをクラッシュさせるマーシャリングバグがあります。Ruby Enterprise Editionでは1.8.7-2010.02以降このバグは修正されています。Ruby 1.9系を使用する場合、Ruby 1.9.1はあからさまなセグメンテーション違反が発生するため使用できません。1.9.3をご使用ください。
1.3 Rakeタスク
Railsにはrails:updateというrakeタスクがあります。Gemfileに記載されているRailsのバージョンを更新後、このrakeタスクを実行してください。
これにより、新しいバージョンでのファイル作成や既存ファイルの変更を対話形式で行なうことができます。
$ rake rails:update
identical config/boot.rb
exist config
conflict config/routes.rb
Overwrite /myapp/config/routes.rb? (enter "h" for help) [Ynaqdh]
force config/routes.rb
conflict config/application.rb
Overwrite /myapp/config/application.rb? (enter "h" for help) [Ynaqdh]
force config/application.rb
conflict config/environment.rb
...
予期しなかった変更が発生した場合は、必ず差分を十分にチェックしてください。
2 Rails 4.1からRails 4.2へのアップグレード
2.1 Web Console gem
最初に、Gemfileのdevelopmentグループにgem 'web-console', '~> 2.0'を追加し、bundle installを実行してください (このgemはRailsを過去のバージョンからアップグレードした場合には含まれないので、手動で追加する必要があります)。gemのインストール完了後、<%= console %>などのコンソールヘルパーへの参照をビューに追加するだけで、どのビューでもコンソールを利用できるようになります。このコンソールは、development環境のビューで表示されるすべてのエラーページにも表示されます。
2.2 Responders gem
respond_withおよびクラスレベルのrespond_toメソッドは、responders gemに移転しました。これらのメソッドを使用したい場合は、Gemfileにgem 'responders', '~> 2.0'と記述するだけで利用できます。今後、respond_with呼び出し、およびクラスレベルのrespond_to呼び出しは、responders gemなしでは動作しません。
# app/controllers/users_controller.rb
class UsersController < ApplicationController
respond_to :html, :json
def show
@user = User.find(params[:id])
respond_with @user
end
end
インスタンスレベルのrespond_toは今回のアップグレードの影響を受けませんので、gemを追加する必要はありません。
# app/controllers/users_controller.rb
class UsersController < ApplicationController
def show
@user = User.find(params[:id])
respond_to do |format|
format.html
format.json { render json: @user }
end
end
end
詳細については#16526を参照してください。
2.3 トランザクションコールバックのエラー処理
現在の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を参照してください。
2.4 テストケースの実行順序
Rails 5.0のテストケースは、デフォルトでランダムに実行されるようになる予定です。この変更に備えて、テスト実行順を明示的に指定するactive_support.test_orderという新しい設定オプションがRails 4.2に導入されました。このオプションを使用すると、たとえばテスト実行順を現行の仕様のままにしておきたい場合は:sortedを指定したり、ランダム実行を今のうちに導入したい場合は:randomを指定したりすることができます。
このオプションに値が指定されていないと、非推奨警告が表示されます。非推奨警告が表示されないようにするには、test環境に以下の記述を追加します。
# config/environments/test.rb Rails.application.configure do config.active_support.test_order = :sorted # `:random`にしてもよい end
2.5 シリアル化属性
serialize :metadata, JSONなどのカスタムコーダーを使用している場合に、シリアル化属性 (serialized attribute) にnilを割り当てると、コーダー内でnil値を渡すのではなく、データベースにNULLとして保存されるようになりました (JSONコーダーを使用している場合の"null"など)。●
2.6 Productionログのレベル
Rails 5のproduction環境では、デフォルトのログレベルが:infoから:debugに変更される予定です。現在のログレベルを変更したくない場合はproduction.rbに以下の行を追加してください。
# `:info`を指定すると現在のデフォルト設定が使用され、 # `:debug`を指定すると今後のデフォルト設定が使用される config.log_level = :info
2.7 Railsテンプレートのafter_bundle
Railsテンプレートを使用し、かつすべてのファイルを (Gitなどで) バージョン管理している場合、生成されたbinstubをバージョン管理システムに追加できません。これは、binstubの生成がBundlerの実行前に行われるためです。
# template.rb
generate(:scaffold, "person name:string")
route "root to: 'people#index'"
$ rake db:migrate
git :init
git add: "."
git commit: %Q{ -m 'Initial commit' }
この問題を回避するために、git呼び出しをafter_bundleブロック内に置くことができるようになりました。こうすることで、binstubの生成が終わってからBundlerが実行されます。
# template.rb
generate(:scaffold, "person name:string")
route "root to: 'people#index'"
rake("db:migrate")
after_bundle do
git :init
git add: "."
git commit: %Q{ -m 'Initial commit' }
end
2.8 RailsのHTMLサニタイザ
アプリケーションで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'
2.9 RailsのDOMのテスト
assert_tagなどを含むTagAssertionsモジュールは非推奨になりました。今後推奨されるのは、ActionViewからrails-dom-testing gemに移行したSelectorAssertionsモジュールのassert_selectメソッドです。
2.10 マスク済み真正性トークン
SSL攻撃を緩和するために、form_authenticity_tokenがマスクされるようになりました。これにより、このトークンはリクエストごとに変更されます。トークンの検証はマスク解除 (unmasking)とそれに続く復号化 (decrypting) によって行われます。この変更が行われたことにより、railsアプリケーション以外のフォームから送信される、静的なセッションCSRFトークンに依存するリクエストを検証する際には、このマスク済み真正性トークンのことを常に考慮する必要がありますのでご注意ください。
2.11 Action Mailer
従来は、メイラークラスでメイラーメソッドを呼び出すと、該当するインスタンスメソッドが直接実行されました。Active Jobと#deliver_laterメソッドの導入に伴い、この動作が変更されました。Rails 4.2では、これらのインスタンスメソッド呼び出しはdeliver_nowまたはdeliver_laterが呼び出されるまで実行延期されます。以下に例を示します。
class Notifier < ActionMailer::Base
def notify(user, ...)
puts "Called"
mail(to: user.email, ...)
end
end
mail = Notifier.notify(user, ...) # Notifier#notifyはこの時点では呼び出されない
mail = mail.deliver_now # "Called"を出力する
この変更によって実行結果が大きく異なるアプリケーションはそれほどないと思われます。ただし、メイラー以外のメソッドを同期的に実行したい場合、かつ従来の同期的プロキシ動作に依存している場合は、これらのメソッドをメイラークラスにクラスメソッドとして直接定義する必要があります。
class Notifier < ActionMailer::Base
def self.broadcast_notifications(users, ...)
users.each { |user| Notifier.notify(user, ...) }
end
end
3 Rails 4.0からRails 4.1へのアップグレード
3.1 リモート <script> タグにCSRF保護を実施
これを行わないと、「なぜかテストがとおらない...orz」ということになりかねません。
JavaScriptレスポンスを伴うGETリクエストもクロスサイトリクエストフォージェリ (CSRF) 保護の対象となりました。この保護によって、第三者のサイトが重要なデータを奪取する目的で自分のサイトのJavaScript URLを参照して実行しようとすることを防止します。
つまり、以下を使用する機能テストと結合テストは
get :index, format: :js
CSRF保護をトリガーするようになります。以下のように書き換え、
xhr :get, :index, format: :js
XmlHttpRequestを明示的にテストしてください。
本当にJavaScriptをリモートの<script>タグから読み込むのであれば、そのアクションではCSRF保護をスキップしてください。
3.2 Spring
アプリケーションのプリローダーとしてSpringを使用する場合は、以下を行う必要があります。
-
gem 'spring', group: :developmentをGemfileに追加する -
bundle installを実行してSpringをインストールする -
bundle exec spring binstub --allを実行してbinstubをSpring化する
ユーザーが定義したRakeタスクはデフォルトでdevelopment環境で動作するようになります。これらのRakeタスクを他の環境でも実行したい場合はSpring READMEを参考にしてください。
3.3 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セクションに新しい鍵を生成します。サーバーを再起動します。
3.4 テストヘルパーの変更
テストヘルパーにActiveRecord::Migration.check_pending!の呼び出しがある場合、これを削除することができます。このチェックはrequire 'rails/test_help'の際に自動的に行われるようになりました。この呼び出しを削除しなくても悪影響が生じることはありません。
3.5 Cookiesシリアライザ
Rails 4.1より前に作成されたアプリケーションでは、Marshalを使用してcookie値を署名済みまたは暗号化したcookies jarにシリアライズしていました。アプリケーションで新しいJSONベースのフォーマットを使用したい場合、以下のような内容を持つイニシャライザファイルを追加できます。
Rails.application.config.action_dispatch.cookies_serializer = :hybrid
これにより、Marshalでシリアライズされた既存のcookiesを、新しいJSONベースのフォーマットに透過的に移行できます。
:jsonまたは:hybridシリアライザを使用する場合、一部のRubyオブジェクトがJSONとしてシリアライズされない可能性があることにご注意ください。たとえば、DateオブジェクトやTimeオブジェクトはstringsとしてシリアライズされ、Hashのキーはstringに変換されます。
class CookiesController < ApplicationController
def set_cookie
cookies.encrypted[:expiration_date] = Date.tomorrow # => Thu, 20 Mar 2014
redirect_to action: 'read_cookie'
end
def read_cookie
cookies.encrypted[:expiration_date] # => "2014-03-20"
end
end
cookieには文字列や数字などの単純なデータだけを保存することをお勧めします。 cookieに複雑なオブジェクトを保存しなければならない場合は、後続のリクエストでcookiesから値を読み出す場合の変換については自分で面倒を見る必要があります。
cookieセッションストアを使用する場合、sessionやflashハッシュについてもこのことは該当します。
3.6 Flash構造の変更
Flashメッセージのキーが文字列に正規化 されました。シンボルまたは文字列のどちらでもアクセスできます。Flashのキーを取り出すと常に文字列になります。
flash["string"] = "a string" flash[:symbol] = "a symbol" # Rails < 4.1 flash.keys # => ["string", :symbol] # Rails >= 4.1 flash.keys # => ["string", "symbol"]
Flashメッセージのキーは文字列と比較してください。
3.7 JSONの扱いの変更点
Rails 4.1ではJSONの扱いが大きく変更された点が4つあります。
3.7.1 MultiJSONの廃止
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 are meant for serializing and deserializing arbitrary Ruby objects and are generally [unsafe]APIは任意のRubyオブジェクトをシリアライズおよびデシリアライズするためのものであり、一般に安全ではありません。
3.7.2 JSON gemの互換性
これまでの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>\""
3.7.3 新しいJSONエンコーダ
Rails 4.1のJSONエンコーダは、JSON gemを使用するように書き直されました。この変更によるアプリケーションへの影響はほとんどありません。ただし、エンコーダが書き直された際に以下の機能がエンコーダから削除されました。
- データ構造の循環検出
-
encode_jsonフックのサポート -
BigDecimalオブジェクトを文字ではなく数字としてエンコードするオプション
アプリケーションがこれらの機能に依存している場合は、activesupport-json_encoder gemをGemfileに追加することで以前の状態に戻すことができます。
3.7.4 TimeオブジェクトのJSON形式表現
日時に関連するコンポーネント(Time、DateTime、ActiveSupport::TimeWithZone)を持つオブジェクトに対して#as_jsonを実行すると、デフォルトでミリ秒単位の精度で値が返されるようになりました。ミリ秒より精度の低い従来方式にしておきたい場合は、イニシャライザに以下を設定してください。
ActiveSupport::JSON::Encoding.time_precision = 0
3.8 インラインコールバックブロックでreturnの使用法
以前のRailsでは、インラインコールバックブロックで以下のようにreturnを使用することが許容されていました。
class ReadOnlyModel < ActiveRecord::Base
before_save { return false } # 良くない
end
この動作は決して意図されたものではありません。ActiveSupport::Callbacksが書き直され、上のような動作はRails 4.1では許容されなくなりました。インラインコールバックブロックでreturn文を書くと、コールバック実行時にLocalJumpErrorが発生するようになりました。
インラインコールバックブロックでreturnを使用している場合、以下のようにリファクタリングすることで、返された値として評価されるようになります。
class ReadOnlyModel < ActiveRecord::Base
before_save { false } # 良い
end
returnを使用したいのであれば、明示的にメソッドを定義することが推奨されます。
class ReadOnlyModel < ActiveRecord::Base
before_save :before_save_callback # 良い
private
def before_save_callback
return false
end
end
この変更は、Railsでコールバックを使用している多くの箇所に適用されます。これにはActive RecordとActive ModelのコールバックやAction Controllerのフィルタ(before_action など)も含まれます。
詳細についてはこのpull requestを参照してください。
3.9 Active Recordフィクスチャで定義されたメソッド
Rails 4.1では、各フィクスチャのERBは独立したコンテキストで評価されます。このため、あるフィクスチャで定義されたヘルパーメソッドは他のフィクスチャでは利用できません。
ヘルパーメソッドを複数のフィクスチャで使用するには、4.1で新しく導入されたActiveRecord::FixtureSet.context_class (test_helper.rb) に含まれるモジュールで定義する必要があります。
module FixtureFileHelpers
def file_sha(path)
Digest::SHA2.hexdigest(File.read(Rails.root.join('test/fixtures', path)))
end
end
ActiveRecord::FixtureSet.context_class.send :include, FixtureFileHelpers
3.10 I18nオプションでavailable_localesリストの使用が強制される
Rails 4.1からI18nオプションenforce_available_localesがデフォルトでtrueになりました。この設定にすると、I18nに渡されるすべてのロケールは、available_localesリストで宣言されていなければ使用できません。
この機能をオフにしてI18nですべての種類のロケールオプションを使用できるようにするには、以下のように変更します。
config.i18n.enforce_available_locales = false
available_localesの強制はセキュリティのために行われていることにご注意ください。つまり、アプリケーションが把握していないロケールを持つユーザー入力が、ロケール情報として使用されることのないようにするためのものです。従って、やむを得ない理由がない限りこのオプションはfalseにしないでください。
3.11 リレーションに対するミューテーターメソッド呼び出し
Relationに#map!や#delete_ifなどのミューテーターメソッド (mutator method) が含まれなくなりました。これらのメソッドを使用したい場合は#to_aを呼び出してArrayに変更してからにしてください。
この変更は、Relationに対して直接ミューテーターメソッドを呼び出すことによる奇妙なバグや混乱を防止するために行われました。
# 以前のミューテーター呼び出し方法 Author.where(name: 'Hank Moody').compact! # 今後のミューテーター呼び出し方法 authors = Author.where(name: 'Hank Moody').to_a authors.compact!
3.12 デフォルトスコープの変更
デフォルトのスコープは、条件を連鎖した場合にオーバーライドされなくなりました。
以前のバージョンでは、モデルでdefault_scopeを定義すると、同じフィールドで連鎖した条件によってオーバーライドされました。現在は、他のスコープと同様、マージされるようになりました。
変更前:
class User < ActiveRecord::Base
default_scope { where state: 'pending' }
scope :active, -> { where state: 'active' }
scope :inactive, -> { where state: 'inactive' }
end
User.all
# SELECT "users".* FROM "users" WHERE "users"."state" = 'pending'
User.active
# SELECT "users".* FROM "users" WHERE "users"."state" = 'active'
User.where(state: 'inactive')
# SELECT "users".* FROM "users" WHERE "users"."state" = 'inactive'
変更後:
class User < ActiveRecord::Base
default_scope { where state: 'pending' }
scope :active, -> { where state: 'active' }
scope :inactive, -> { where state: 'inactive' }
end
User.all
# SELECT "users".* FROM "users" WHERE "users"."state" = 'pending'
User.active
# SELECT "users".* FROM "users" WHERE "users"."state" = 'pending' AND "users"."state" = 'active'
User.where(state: 'inactive')
# SELECT "users".* FROM "users" WHERE "users"."state" = 'pending' AND "users"."state" = 'inactive'
以前と同じ動作に戻したい場合は、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'
3.13 文字列からのコンテンツ描出
Rails 4.1のrenderに:plain、:html、:bodyオプションが導入されました。以下のようにコンテンツタイプを指定できるため、文字列ベースのコンテンツ表示にはこれらのオプションの使用が推奨されます。
* render :plainを実行するとcontent typeはtext/plainに設定される
* render :htmlを実行するとcontent typeはtext/htmlに設定される
* render :bodyを実行した場合、content typeヘッダーは「設定されない」
セキュリティ上の観点から、レスポンスのbodyにマークアップを含めない場合にはrender :plainを使用すべきです。これによって多くのブラウザが安全でないコンテンツをエスケープできるからです。
今後のバージョンでは、render :textは非推奨にされる予定です。今のうちに、正しい:plain、:html、:bodyオプションに切り替えてください。
render :textを使用するとtext/htmlで送信されるため、セキュリティ上のリスクが生じる可能性があります。
3.14 PostgreSQLのデータ型'json'と'hstore'について
Rails 4.1では、PostgreSQLのjsonカラムとhstoreカラムを、文字列をキーとするRubyのHashに対応付けるようになりました。
なお、以前のバージョンではHashWithIndifferentAccessが使用されていました。この変更は、Rails 4.1以降ではシンボルを使用してこれらのデータ型にアクセスできなくなるということを意味します。store_accessorsメソッドはjsonカラムやhstoreカラムに依存しているので、同様にシンボルでのアクセスが行えなくなります。今後は常に文字列をキーにするようにしてください。
3.15 ActiveSupport::Callbacksでは明示的にブロックを使用すること
Rails 4.1からはActiveSupport::Callbacks.set_callbackの呼び出しの際に明示的にブロックを渡すことが期待されます。これは、ActiveSupport::CallbacksがRails 4.1リリースにあたって大幅に書き換えられたことによるものです。
# Rails 4.0の場合
set_callback :save, :around, ->(r, &block) { stuff; result = block.call; stuff }
# Rails 4.1の場合
set_callback :save, :around, ->(r, block) { stuff; result = block.call; stuff }
4 Rails 3.2からRails 4.0へのアップグレード
Railsアプリケーションのバージョンが3.2より前の場合、まず3.2へのアップグレードを完了してからRails 4.0へのアップグレードを開始してください。
以下の変更は、アプリケーションをRails 4.0にアップグレードするためのものです。
4.1 HTTP PATCH
Rails 4では、config/routes.rbでRESTfulなリソースが宣言されたときに、更新用の主要なHTTP verbとしてPATCHが使用されるようになりました。updateアクションは従来通り使用でき、PUTリクエストは今後もupdateアクションにルーティングされます。
標準的なRESTfulのみを使用しているのであれば、これに関する変更は不要です。
resources :users
<%= form_for @user do |f| %>
class UsersController < ApplicationController
def update
# 変更不要:PATCHが望ましいがPUTも使用できる
end
end
ただし、form_forを使用してリソースを更新しており、PUT HTTPメソッドを使用するカスタムルーティングと連動しているのであれば、変更が必要です。
resources :users, do put :update_name, on: :member end
<%= form_for [ :update_name, @user ] do |f| %>
class UsersController < ApplicationController
def update_name
# 変更が必要: form_forは、存在しないPATCHルートを探そうとする
end
end
このアクションがパブリックなAPIで使用されておらず、HTTPメソッドを自由に変更できるのであれば、ルーティングを更新して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ブログの この記事 を参照してください。
4.1.1 メディアタイプに関するメモ
PATCH verbに関する追加情報 PATCHでは異なるメディアタイプを使用する必要がある。JSON Patch などが該当します。RailsはJSON Patchをネイティブではサポートしませんが、サポートは簡単に追加できます。
# コントローラに以下を書く
def update
respond_to do |format|
format.json do
# 部分的な変更を行なう
@article.update params[:article]
end
format.json_patch do
# 何か気の利いた変更を行なう
end
end
end
# config/initializers/json_patch.rb に以下を書く
Mime::Type.register 'application/json-patch+json', :json_patch
JSON Patchは最近RFC化されたばかりなのでRubyライブラリはそれほどありません。Aaron Pattersonの hana gemが代表的ですが、最新の仕様変更をすべてサポートしているわけではありません。
4.2 Gemfile
Rails 4.0ではassetsグループがGemfileから削除されました。アップグレード時にはこの記述をGemfileから削除する必要があります。アプリケーションのconfig/application.rbファイルも以下のように更新する必要があります。
# Require the gems listed in Gemfile, including any gems # you've limited to :test, :development, or :production. Bundler.require(:default, Rails.env)
4.3 vendor/plugins
Rails 4.0 では vendor/plugins 読み込みのサポートは完全に終了しました。使用するプラグインはすべてgemに展開してGemfileに追加しなければなりません。理由があってプラグインをgemにしないのであれば、プラグインをlib/my_plugin/*に移動し、適切な初期化の記述をconfig/initializers/my_plugin.rbに書いてください。
4.4 Active Record
関連付けに関する若干の不整合 のため、Rails 4.0ではActive Recordからidentity mapが削除されました。この機能をアプリケーションで手動で有効にしたい場合は、今や無効になった
config.active_record.identity_mapを削除する必要があるでしょう。コレクション関連付けの
deleteメソッドは、Fixnumや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_...becomeswhere(...). -
find_last_by_...becomeswhere(...).last. -
scoped_by_...becomeswhere(...) -
find_or_initialize_by_...に代えてfind_or_initialize_by(...)を使用` -
find_or_create_by_...に代えてfind_or_create_by(...)を使用`
-
旧来のfinderが配列を返していたのに対し、
where(...)はリレーションを返します。Arrayが必要な場合は,where(...).to_aを使用してください。これらの同等なメソッドが実行するSQLは、従来の実装と同じではありません。
旧来のfinderを再度有効にしたい場合は、activerecord-deprecated_finders gem を使用できます。
4.5 Active Resource
Rails 4.0ではActive Resourceがgem化されました。この機能が必要な場合はActive Resource gem をGemfileに追加できます。
4.6 Active Model
Rails 4.0では
ActiveModel::Validations::ConfirmationValidatorにエラーがアタッチされる方法が変更されました。確認バリデーションが失敗したときに、attributeではなく:#{attribute}_confirmationにアタッチされるようになりました。Rails 4.0の
ActiveModel::Serializers::JSON.include_root_in_jsonのデフォルト値がfalseに変更されました。これにより、Active Model SerializersとActive Recordオブジェクトのデフォルトの動作が同じになりました。これにより、config/initializers/wrap_parameters.rbファイルの以下のオプションをコメントアウトしたり削除したりできるようになりました。
# Disable root element in JSON by default. # ActiveSupport.on_load(:active_record) do # self.include_root_in_json = false # end
4.7 Action Pack
- Rails 4.0から
ActiveSupport::KeyGeneratorが導入され、署名付きcookiesの生成と照合などに使用されるようになりました。Rails 3.xで生成された既存の署名付きcookiesは、既存のsecret_tokenはそのままにしてsecret_key_baseを新しく追加することで透過的にアップグレードされます。
# config/initializers/secret_token.rb Myapp::Application.config.secret_token = 'existing secret token' Myapp::Application.config.secret_key_base = 'new secret key base'
注意:secret_key_baseを設定するのは、Rails 4.xへのユーザーベースの移行が100%完了し、Rails 3.xにロールバックする必要が完全になくなってからにしてください。これは、Rails 4.xの新しいsecret_key_baseを使用して署名されたcookiesにはRails 3.xのcookiesとの後方互換性がないためです。他のアップグレードが完全に完了するまでは、既存のsecret_tokenをそのままにしてsecret_key_baseを設定せず、非推奨警告を無視するという選択肢もあります。
外部アプリケーションやJavaScriptからRailsアプリケーションの署名付きセッションcookies (または一般の署名付きcookies) を読み出せる必要がある場合は、これらの問題を切り離すまではsecret_key_baseを設定しないでください。
- Rails 4.0では、
secret_key_baseが設定されているとcookieベースのセッションの内容が暗号化されます。Rails 3.xではcookieベースのセッションへの署名は行われますが暗号化は行われません。署名付きcookiesは、そのRailsアプリケーションで生成されたことが確認でき、不正が防止されるという意味では安全です。しかしセッションの内容はエンドユーザーから見えてしまいます。内容を暗号化することで懸念を取り除くことができ、パフォーマンスの低下もそれほどありません。
セッションcookiesを暗号化する方法の詳細についてはPull Request #9978 を参照してください。
Rails 4.0 では
ActionController::Base.asset_pathオプションが廃止されました。代りにアセットパイプライン機能をご利用ください。Rails 4.0では
ActionController::Base.page_cache_extensionオプションが非推奨になりました。代りにActionController::Base.default_static_extensionをご利用ください。Rails 4.0のAction PackからActionとPageのキャッシュ機能が取り除かれました。コントローラで
caches_actionを使用したい場合はactionpack-action_cachinggemを、caches_pagesを使用したい場合はactionpack-page_cachinggemをそれぞれGemfileに追加する必要があります。Rails 4.0からXMLパラメータパーサーが取り除かれました。この機能が必要な場合は
actionpack-xml_parsergemを追加する必要があります。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メソッドで使用することで、作成されるルーティングを制限することができます。詳細は Routing Guide を参照。
- Rails 4.0ではunicode文字のルーティングの描出方法が変更されました。unicode文字を使用するルーティングを直接描出できるようになりました。既にこのようなルーティングを使用している場合は、以下の変更が必要です。
get Rack::Utils.escape('こんにちは'), controller: 'welcome', action: 'index'
上のコードは以下のように変更する必要があります。
get 'こんにちは', controller: 'welcome', action: 'index'
- Rails 4.0でルーティングに
matchを使用する場合は、リクエストメソッドの指定が必須となりました。以下に例を示します。
# Rails 3.x match '/' => 'root#index' # 上のコードは以下のように変更する必要があります。 match '/' => 'root#index', via: :get # または get '/' => 'root#index'
- Rails 4.0から
ActionDispatch::BestStandardsSupportミドルウェアが削除されました。<!DOCTYPE html>は既に http://msdn.microsoft.com/en-us/library/jj676915(v=vs.85).aspx の標準モードをトリガするようになり、ChromeFrameヘッダはconfig.action_dispatch.default_headersに移動されました。
アプリケーションコード内にあるこのミドルウェアへの参照はすべて削除する必要がありますので注意が必要です。例:
# 例外発生 config.middleware.insert_before(Rack::Lock, ActionDispatch::BestStandardsSupport)
環境設定も確認し、config.action_dispatch.best_standards_supportがある場合は削除します。
Rails 4.0のアセットのプリコンパイルでは、
vendor/assetsおよびlib/assetsにある非JS/CSSアセットを自動的にはコピーしなくなりました。Railsアプリケーションとエンジンの開発者は、これらのアセットを手動でapp/assetsに置き、config.assets.precompileを設定してください。Rails 4.0では、リクエストされたフォーマットがアクションで扱えなかった場合に
ActionController::UnknownFormatが発生するようになりました。デフォルトでは、この例外は406 Not Acceptable応答として扱われますが、この動作をオーバーライドすることができます。Rails 3では常に406 Not Acceptableが返されます。オーバーライドはできません。Rails 4.0では、
ParamsParserがリクエストパラメータをパースできなかった場合に一般的なActionDispatch::ParamsParser::ParseError例外が発生するようになりました。MultiJson::DecodeErrorのような低レベルの例外の代りにこの例外をレスキューすることができます。Rails 4.0では、URLプレフィックスで指定されたアプリケーションにエンジンがマウントされている場合に
SCRIPT_NAMEが正しく入れ子になるようになりました。今後はURLプレフィックスの上書きを回避するためにdefault_url_options[:script_name]を設定する必要はありません。Rails 4.0では
ActionDispatch::Integrationの導入に伴いActionController::Integrationが非推奨となりました。Rails 4.0では
ActionDispatch::IntegrationTestの導入に伴いActionController::IntegrationTestは非推奨となりました。Rails 4.0では
ActionDispatch::PerformanceTestの導入に伴いActionController::PerformanceTestが非推奨となりました。Rails 4.0では
ActionDispatch::Requestの導入に伴いActionController::AbstractRequestが非推奨となりました。Rails 4.0では
ActionDispatch::Requestの導入に伴いActionController::Requestが非推奨となりました。Rails 4.0では
ActionDispatch::Responseの導入に伴いActionController::AbstractResponseが非推奨となりました。Rails 4.0では
ActionDispatch::Responseの導入に伴いActionController::Responseが非推奨となりました。Rails 4.0では
ActionDispatch::Routingの導入に伴いActionController::Routingが非推奨となりました。
4.8 Active Support
Rails 4.0ではERB::Util#json_escapeのエイリアスjが廃止されました。このエイリアスjは既にActionView::Helpers::JavaScriptHelper#escape_javascriptで使用されているためです。
4.9 ヘルパーの読み込み順序
Rails 4.0では複数のディレクトリからのヘルパーの読み込み順が変更されました。以前はすべてのヘルパーをいったん集めてからアルファベット順にソートしていました。Rails 4.0にアップグレードすると、ヘルパーは読み込まれたディレクトリの順序を保持し、ソートは各ディレクトリ内でのみ行われます。helpers_pathパラメータを明示的に使用している場合を除いて、この変更はエンジンからヘルパーを読み込む方法にしか影響しません。ヘルパー読み込みの順序に依存している場合は、アップグレード後に正しいメソッドが使用できているかどうかを確認する必要があります。エンジンが読み込まれる順序を変更したい場合は、config.railties_order= メソッドを使用できます。
4.10 Active Record ObserverとAction Controller Sweeper
Active Record ObserverとAction Controller Sweeperはrails-observers gemに切り出されました。これらの機能が必要な場合はrails-observers gemを追加してください。
4.11 sprockets-rails
-
assets:precompile:primaryおよびassets:precompile:allは削除されました。assets:precompileを代りに使用してください。 -
config.assets.compressオプションは、たとえば以下のようにconfig.assets.js_compressorに変更する必要があります。
config.assets.js_compressor = :uglifier
4.12 sass-rails
- 引数を2つ使用する
asset-urlは非推奨となりました。たとえば、asset-url("rails.png", image)はasset-url("rails.png")とする必要があります。
5 Rails 3.1からRails 3.2へのアップグレード
Railsアプリケーションのバージョンが3.1より前の場合、まず3.1へのアップグレードを完了してからRails 3.2へのアップグレードにとりかかってください。
Railsアプリケーションのバージョンが3.1よりも古い場合、まず3.1へのアップグレードを完了してからRails 3.2へのアップグレードを開始してください。
5.1 Gemfile
Gemfileを以下のように変更します。
gem 'rails', '3.2.21' group :assets do gem 'sass-rails', '~> 3.2.6' gem 'coffee-rails', '~> 3.2.2' gem 'uglifier', '>= 1.0.3' end
5.2 config/environments/development.rb
development環境にいくつかの新しい設定を追加する必要があります。
# Active Recordのモデルをマスアサインメントから保護するために例外を発生する config.active_record.mass_assignment_sanitizer = :strict # クエリの実行計画 (クエリプラン) を現在より多く出力する # (SQLite、MySQL、PostgreSQLで動作) config.active_record.auto_explain_threshold_in_seconds = 0.5
5.3 config/environments/test.rb
mass_assignment_sanitizer設定をconfig/environments/test.rbにも追加する必要があります。
# Active Recordのモデルをマスアサインメントから保護するために例外を発生する config.active_record.mass_assignment_sanitizer = :strict
5.4 vendor/plugins
vendor/plugins はRails 3.2で非推奨となり、Rails 4.0では完全に削除されました。Rails 3.2へのアップグレードでは必須ではありませんが、今のうちにプラグインをgemにエクスポートしてGemfileに追加するのがよいでしょう。理由があってプラグインをgemにしないのであれば、プラグインをlib/my_plugin/*に移動し、適切な初期化の記述をconfig/initializers/my_plugin.rbに書いてください。
5.5 Active Record
:dependent => :restrictオプションはbelongs_toから削除されました。関連付けられたオブジェクトがある場合にこのオブジェクトを削除したくない場合は、:dependent => :destroyを設定し、関連付けられたオブジェクトのdestroyコールバックとの関連付けがあるかどうかを確認してからfalseを返すようにします。
6 Rails 3.0からRails 3.1へのアップグレード
Railsアプリケーションのバージョンが3.0より前の場合、まず3.0へのアップグレードを完了してからRails 3.1へのアップグレードにとりかかってください。
以下の変更は、Rails 3.1.xの最新版であるRails 3.1.12にアップグレードするためのものです。
6.1 Gemfile
Gemfileを以下のように変更します。
gem 'rails', '3.1.12' gem 'mysql2' # 新しいアセットパイプラインで必要 group :assets do gem 'sass-rails', '~> 3.1.7' gem 'coffee-rails', '~> 3.1.1' gem 'uglifier', '>= 1.0.3' end # Rails 3.1からjQueryがデフォルトのJavaScriptライブラリになる gem 'jquery-rails'
6.2 config/application.rb
アセットパイプラインを使用するために以下の変更が必要です。
config.assets.enabled = true config.assets.version = '1.0'
Railsアプリケーションでリソースのルーティングに"/assets"ルートを使用している場合、コンフリクトを避けるために以下の変更を加えます。
# '/assets'のデフォルト config.assets.prefix = '/asset-files'
6.3 config/environments/development.rb
RJS の設定config.action_view.debug_rjs = trueを削除してください。
アセットパイプラインを有効にしている場合は以下の設定を追加します。
# 開発環境ではアセットを圧縮しない config.assets.compress = false # アセットで読み込んだ行を展開する config.assets.debug = true
6.4 config/environments/production.rb
以下の変更はほとんどがアセットパイプライン用です。詳細については アセットパイプライン ガイドを参照してください。
# JavaScriptとCSSを圧縮する
config.assets.compress = true
# プリコンパイル済みのアセットが見当たらない場合にアセットパイプラインにフォールバックしない
config.assets.compile = false
# アセットURLのダイジェストを生成する
config.assets.digest = true
# Rails.root.join("public/assets")へのデフォルト
# config.assets.manifest = 該当するパス
# 追加のアセット (application.js、application.cssおよびすべての非JS/CSSが追加済み) をプリコンパイルする
# config.assets.precompile += %w( search.js )
# アプリケーションへのすべてのアクセスを強制的にSSLにし、Strict-Transport-Securityとセキュアクッキーを使用する
# config.force_ssl = true
6.5 config/environments/test.rb
テスト環境に以下を追加することでテストのパフォーマンスが向上します。
# Cache-Controlを使用するテストで静的アセットサーバーを構成し、パフォーマンスを向上させる config.serve_static_assets = true config.static_cache_control = 'public, max-age=3600'
6.6 config/initializers/wrap_parameters.rb
ネストしたハッシュにパラメータを含めたい場合は、このファイルに以下のコンテンツを含めて追加します。新しいアプリケーションではこれがデフォルトになります。
# このファイルを変更後サーバーを必ず再起動してください。 # このファイルにはActionController::ParamsWrapper用の設定が含まれており # デフォルトでオンになっています。 # JSON用にパラメータをラップします。:formatに空配列を設定することで無効にできます。 ActiveSupport.on_load(:action_controller) do wrap_parameters format: [:json] end # JSONのルート要素をデフォルトで無効にする ActiveSupport.on_load(:active_record) do self.include_root_in_json = false end
6.7 config/initializers/session_store.rb
何らかの新しいセッションキーを設定するか、すべてのセッションを削除するかのどちらかにする必要があります。
# config/initializers/session_store.rbに以下を設定する AppName::Application.config.session_store :cookie_store, key: 'SOMETHINGNEW'
または
$ bin/rake db:sessions:clear
6.8 ビューのアセットヘルパー参照から:cacheオプションと:concatオプションを削除する
- Asset Pipelineの:cacheオプションと:concatは廃止されました。ビューからこれらのオプションを削除してください。
フィードバックについて
本ガイドの訳文およびソースコードは、GitHub上の yasslab/railsguides.jp で管理・公開されております。 本ガイドを読んで、誤字・脱字・誤訳などを見かけましたら、上記リポジトリにてお気軽に Issue を出して頂けると大変嬉しいです。また、「Pull Request を送りたい!」という場合には、Ruby on Railsガイドのガイドラインと、READMEに記載されている「翻訳の流れ」をご参考にしてください。
なお、原著レベルでの間違いを見つけましたら、原著へのフィードバック方法 (documentation contributions) をご参考にしてください。
本ガイドの品質向上に向けて、皆さまのご協力が得られれば幸いです。よろしくお願い致します。