Rails 4.0 にアップグレードした
最近、Rails 1.2 で開発をスタートした Rails 3.2 のアプリケーションを Rails 4.0 にアップグレードした。
その時に修正が必要になったところのメモを残しておく。
- ActiveSupport
- ActiveModel
- ActiveRecord
- lambda / proc を利用しない scope が deprecated になった
- has_many, belongs_to などが第2引数に scope を受け取るようになった
- first(...), find(:first, ...) が deprecated になった
- all(...), find(:all, ...) が deprecated になった
- find(id, ...) が deprecated になった
- find_all_by_..., find_or_initialize_by_... などの dynamic finder が deprecated になった
- scoped / with_scope / with_exclusive_scope が deprecated になった
- order が Hash を受け付けるようになった
- where.not が利用できるようになった
- {Model}::Type クラスが作成されるようになった
- acts_as_paranoid が Rails 4 に対応していない
- set_table_name が削除された
- ActiveRecord::Base#connection が deprecated になった
- ActionPack
- Strong Parameters
- routes.rb で via なしの match が利用できなくなった
- update 時の HTTP method が PUT から PATCH になった
- spec で assigns から返ってくる Hash が HashWithIndifferentAccess に変換されるバグが修正された
- link_to_function, button_to_function が deprecated になった
- text_field, text_area のデフォルトサイズ指定がなくなった
- 問題のなかった eruby がエラーになった
- ActionPack その他
- Railties
- Rack
- Sprockets
- ActiveResource
- acts_as_list
- その他
ActiveSupport ^
ActiveSupport::JSON.encode でマルチバイト文字が escape されなくなった ^
https://github.com/rails/rails/commit/8f8397e0a4
マルチバイト文字をエスケープしたくない場面で独自拡張をしていたが、その必要がなくなった。
対応
独自拡張を削除した。
Range#step の拡張 (blockless_step) が削除された ^
https://github.com/rails/rails/issues/6297
この拡張のせいで Rails 3.2 までは
(0..10).step(2) # => #<Enumerator: 0..10:step(2)>
となるべきところが
(0..10).step(2) # => [0, 2, 4, 6, 8, 10]
となってしまっていた。
対応
Range#step を使っているのに Array を期待してしまっていたところに明示的に .to_a
を追加した。
ActiveModel ^
validates_format_of で multiline option なしに ^
$
を利用できなくなった ^
https://github.com/rails/rails/commit/bc7c0b5c10
対応
\A
\z
に書き換えた。
validates_confirmation_of のエラーメッセージが追加される attribute が password
から password_confirmation
に変更された ^
https://github.com/rails/rails/pull/5942
対応
config/locale/ja.yml
に password_confirmation
の表記を追加した。
ja:
activerecord:
user:
password: パスワード
+ password_confirmation: パスワード(確認)
ActiveRecord ^
lambda / proc を利用しない scope が deprecated になった ^
scope :active, where(active: true)
は deprecated.
対応
scope :active, -> { where(active: true) }
に書き換えた。
has_many, belongs_to などが第2引数に scope を受け取るようになった ^
has_many :users, order: :name
は deprecated.
対応
has_many :users, -> { order(:name) }
に書き換えた。
first(...), find(:first, ...) が deprecated になった ^
User.first(conditions: { active: true }) User.find(:first, conditions: { active: true })
は deprecated.
activerecord-deprecated_finders gem に移されている。
対応
Uesr.find_by(active: true)
に書き換えた。
all(...), find(:all, ...) が deprecated になった ^
User.all(conditions: { active: true }) User.find(:all, conditions: { active: true })
は deprecated.
activerecord-deprecated_finders gem に移されている。
対応
Uesr.where(active: true).to_a # ほとんどの場所では to_a は必要ない
に書き換えた。
find(id, ...) が deprecated になった ^
Group.find(1, include: :users)
は deprecated.
activerecord-deprecated_finders gem に移されている。
対応
Group.includes(:users).find(1)
に書き換えた。
find_all_by_..., find_or_initialize_by_... などの dynamic finder が deprecated になった ^
User.find_all_by_active(true) User.scoped_by_active(true) User.find_or_initialize_by_name('john')
は deprecated.
activerecord-deprecated_finders gem に移されている。
利用していなかったけど find_last_by_...
, find_or_create_by_...
も同様。
ちなみに find_by_...
は Rails 4.0 では deprecated になっていない。
対応
User.where(active: true).to_a # ほとんどの場所では to_a は必要ない User.where(active: true) User.find_or_initialize_by(name: 'john')
に書き換えた。
scoped / with_scope / with_exclusive_scope が deprecated になった ^
# 例えば、初期値を設定して new したいとき User.scoped(conditions: { active: true }).new User.with_scope(create: { active: true }) { User.new } # 例えば、default_scope を無視して取得したいとき User.with_exclusive_scope { User.all }
は deprecated.
activerecord-deprecated_finders gem に移されている。
対応
# 例えば、初期値を設定して new したいとき User.where(active: true).new User.where(active: true).scoping { User.new } # 例えば、default_scope を無視して取得したいとき User.unscoped
に書き換えた。
order が Hash を受け付けるようになった ^
User.order('users.id DESC') # or User.order(User.arel_table[:id].desc)
を以下のように書けるようになった。
User.order(id: :desc)
また order
に Symbol を渡すだけでテーブル名も付加してくれるようになった。
where.not が利用できるようになった ^
User.where('users.deleted_at IS NOT NULL') # or User.where(User.arel_table[:deleted_at].not_eq(nil))
を以下のように書けるようになった。
User.where.not(deleted_at: nil)
{Model}::Type クラスが作成されるようになった ^
class Foo < ActiveRecord::Base end
とすると Foo::Type
が作成される。
これは ActiveRecord::AttributeMethods::Serialization::Type
というクラスが追加されたため。
アプリケーション側ですでに Foo::Type
を作成していたため問題が起きた。
対応
Foo::Type
を Foo::BarType
などに名前を変更した。
acts_as_paranoid が Rails 4 に対応していない ^
対応
paranoia を使った。
paranoia は datetime 型しか対応しておらず、アプリケーションでは boolean を使っているという別の問題が発生したので、機能追加して凌いだ。
set_table_name が削除された ^
https://github.com/rails/rails/commit/9add7608f1
Rails 3.2 の時から Deprecation Warning は出ていたが、migration で利用されていたため見落としていた。
対応
self.table_name =
に書き換えた。
ActiveRecord::Base#connection が deprecated になった ^
https://github.com/rails/rails/commit/992d87db02
対応
self.class.connection
に書き換えた。
ActionPack ^
Strong Parameters ^
対応
普通はまじめに Strong Parameters 対応をするか protected_attributes gem を使うかだろうけど、 Rails 1.2 時代から作っているせいで attr_accessible, attr_protected を使わずに独自実装(role 指定可能な attr_accessible に近いもの)していたため、とりあえず無効にした。
config.action_controller.permit_all_parameters = true
徐々に Strong Parameters に移行していく予定。
routes.rb で via なしの match が利用できなくなった ^
https://github.com/rails/rails/issues/5964
対応
get
, post
, patch
など適切なものに書き換えた。
複数 HTTP method を受け付けるような action は via をつけても良いが、action を分割した方がより良いので controller 含め修正した。
update 時の HTTP method が PUT から PATCH になった ^
form_for
によって生成される form もそうなるため、
routes.rb
で resources
で指定しているものは問題ないが、
put 'user/:id', to: 'users#update'
などと直接記述している場合、404 になる。
対応
patch に書き換えた。
patch 'user/:id', to: 'users#update'
spec で assigns から返ってくる Hash が HashWithIndifferentAccess に変換されるバグが修正された ^
https://github.com/rails/rails/pull/5082
### controller @foo = {} ### spec # Rails 3.2 assings(:foo).class # => HashWithIndifferentAccess # Rails 4.0 assings(:foo).class # => Hash
対応
Hash として扱うように spec を修正
link_to_function, button_to_function が deprecated になった ^
https://github.com/rails/rails/commit/5d1528740a
対応
link_to
, button_tag
で書き換えた。
-<%= button_to_function 'click!', 'alert("hello")' %> +<%= button_tag 'click!', onclick: 'alert("hello")' %>
button_tag
は <input>
タグから <button>
タグになること、それにより <form>
内で <input type="submit">
より前に置くと Enter キーに submit より優先して反応することに注意する必要がある。
text_field, text_area のデフォルトサイズ指定がなくなった ^
Rails 3 までは
DEFAULT_FIELD_OPTIONS = { "size" => 30 } DEFAULT_TEXT_AREA_OPTIONS = { "cols" => 40, "rows" => 20 }
と定義されていたが、 Rails 4.0 では綺麗さっぱりなくなり、デフォルトに頼っていた text_field, text_area が小さく表示されるようになった。
対応
以下の monkey patch を作成した。(prepend が public なのは Ruby 2.1 からなので注意)
module TextFieldWithDefaultSize DEFAULT_FIELD_OPTIONS = { 'size' => 30 } def render @options = @options.stringify_keys unless @options.key?('size') @options['size'] = @options['maxlength'] || DEFAULT_FIELD_OPTIONS['size'] end super end end module TextAreaWithDefaultSize DEFAULT_TEXT_AREA_OPTIONS = { 'cols' => 40, 'rows' => 20 } def render @options = DEFAULT_TEXT_AREA_OPTIONS.merge(@options.stringify_keys) super end end require 'action_view/helpers/tags/text_field' require 'action_view/helpers/tags/text_area' module ActionView::Helpers::Tags TextField.prepend TextFieldWithDefaultSize TextArea.prepend TextAreaWithDefaultSize end
問題のなかった eruby がエラーになった ^
以下のコードがエラーになるようになった。
<%-# comment %(<%= 1 %>) -%> 2 <%= 3 %> 4
これは Rails 3.2 では 3 4
と出力されるが Rails 4.0 ではエラーになる。
既存のコードを残したまま <%= 1 %>
の部分をコメントアウトしたつもりらしい。むしろこれが今まで動いてたのがすごい。
どの修正が原因かは追っていない。(Erubis の version は上がってない)
対応
必要のないコメントだったので削除した。
ActionPack その他 ^
- params が ActionController::Parameters になった
- routes.rb で
root
のto:
,via: :get
が必要なくなった hash_for_.*_(path|url)
method が削除された (https://github.com/rails/rails/commit/02f2e3d538)- ActionView::Helpers::FormBuilder#initialize の第5引数が廃止になった (https://github.com/rails/rails/commit/56089ca986)
Railties ^
Gemfile から assets group が削除された ^
https://github.com/rails/rails/commit/49c4af43ec
production に必要のない gem (sass-rails, uglifier, coffee-rails) が assets group から外されたため、production 環境でインストールされる上に、ExecJS に Could not find a JavaScript runtime.
と怒られる。
対応
--- a/Gemfile +++ b/Gemfile @@ -9,8 +9,8 @@ # Use SCSS for stylesheets -gem 'sass-rails', '~> 4.0.0' +gem 'sass-rails', '~> 4.0.0', group: :assets # Use Uglifier as compressor for JavaScript assets -gem 'uglifier', '>= 1.3.0' +gem 'uglifier', '>= 1.3.0', group: :assets # Use CoffeeScript for .js.coffee assets and views -gem 'coffee-rails', '~> 4.0.0' +gem 'coffee-rails', '~> 4.0.0', group: :assets
として、
# build 環境 RAILS_ENV=production bin/rake assets:precompile # production 環境 bundle install --without development test assets
とするようにした。
Rails 3.2 で行われてたような config/application.rb
の Bundler.require
の修正や、rake assets:precompile
時の RAILS_GROUP=assets
は特に必要なく動いている。
おそらく Rails 4.0 では Bundler を以下のように利用しているからだと思われる。
config/boot.rb
でBundler.setup
を引数なしで実行するBundler.setup
は.bundle/config
のBUNDLE_WITHOUT
で指定した group 以外の gem を$LOAD_PATH
に追加するBUNDLE_WITHOUT
はbundle install --without <group>
で指定した group が記述されている
config/application.rb
でRails.env
に合わせてBundle.require
を実行するBundle.require
は引数で指定された group の gem を require する
そのため、この対応で sass-rails などは config/application.rb
時点では require されなくなるが、おそらく必要なときに適切に require されるため、development/test 環境、rake assets:precompile で問題は起きていない。
Rack ^
v1.4.5 -> v1.5.2
Rack::Session::Abstract::SessionHash が Hash を継承しなくなった ^
https://github.com/rack/rack/commit/e5b4d961e5
この影響で以下のような spec が動かなくなった。
session.should include('foo' => :bar) session.should include(baz: :qux)
対応
以下のように書き換えた。
session.to_hash.should include('foo' => :bar) session.to_hash.should include('baz' => :qux)
対応過程で Rails 4 で修正された reset_session で session が壊れるバグも踏んだ。
Sprockets ^
v2.2.2 -> v2.10.1
config.assets.precompile にセットした filter が full path を受け取れるようになった ^
https://github.com/sstephenson/sprockets/commit/93e5103bc9
この拡張のお陰で app/assets と vendor/assets で挙動を変えるというようなことが簡単に行えるようになった。
しかし、この影響で config.assets.precompile に call 可能な object を渡すと arity method が呼ばれるようになった。
config.assets.precompile << -> path { ... }
であれば気にしなくてよいが
class PrecompileFilter def call(path) end end config.assets.precompile << PrecompileFilter.new
としていた場合に NoMethodError: undefined method 'arity'
となってしまう。
対応
以下を追加
def arity method(:call).arity end
ActiveResource ^
Rails から削除された ^
対応
gem 'activeresource'
acts_as_list ^
v0.2.0 -> v0.3.0 (Rails 4 対応版)
callback が Symbol から String になった ^
https://github.com/swanandp/acts_as_list/commit/923484eba1
spec で acts_as_list の機能を一時的に off にしたいときに
skip_callback :create, :before, :add_to_list_top
としているところでエラーになった。
対応
skip_callback :create, :before, '(add_to_list_top)'
と書かないといけなくなった。
(これは pull req 案件だろうけど出してない。そのうち直ってまた修正が必要になりそうな気がする。)
その他 ^
- activerecord-import 0.3.1 -> 0.4.1 (Rails 4 対応版)
- rails-i18n 3.0.0 -> 4.0.0 (Rails 4 対応版)
- i18n-js の挙動が微妙に変わった
- .gitignore に /app/assets/javascripts/i18n/ を追加した
- assets:precompile 前に i18n:js:export の実行が必要になった