Rails 3.2 -> Rails 4.0 アップデートメモ: Rails update (3)

はじめに

Rails 3.2 から 4.0 は、大幅な変更が入っているので、Rails アップグレードガイド - Railsガイドを確認しながら進めていきます。

rails 4.0.13 へのアップデート

まず、Gemfile の Rails のバージョンを変更します。

gem 'rails', '4.0.13'

bundle update で一式をアップデートします。

bundle update

3.2 の時と同様に vimdiff で rails:update を実施します。 bundle exec が必要になっていました。 実行したところ、config/application.rb の 55 行目でエラーが出ています。 とりあえず、コメントアウトして先に進めます。

env THOR_DIFF=vimdiff bundle exec rake rails:update
rake aborted!
NoMethodError: undefined method `[]=' for nil:NilClass
/opt/webcitc/config/application.rb:55:in `<class:Application>'

続けたところ、attr_accessible でエラーになりました。アップデートガイドにも以下のように書かれています。全てのモデルから attr_accessible を削除します。

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

hkob@dockerhost /o/webcitc> env THOR_DIFF=vimdiff bundle exec rake rails:update
rake aborted!
`attr_accessible` is extracted out of Rails into a gem. Please use new recommended protection model for params(strong_parameters) or add `protected_attributes` to your Gemfile to use old one.
/opt/webcitc/vendor/bundle/ruby/2.2.0/gems/activemodel-4.0.13/lib/active_model/deprecated_mass_assignment_security.rb:14:in `attr_accessible'
/opt/webcitc/app/models/address_tel.rb:14:in `<class:AddressTel>'

また、PostgreSQL 10 対策もしておきます。かなり多くの deprecation warning が出るので、ドキュメントを見ながら潰していきます。 とりあえず、be rspec が実行できるところまで辿り着きました。

spring の導入

spring が標準導入されるのは、Rails 4.1 からですが 4.0 の時には使えていたはずです。テスト高速化のために、フライングで導入しようと思います。

group :development, :test, :test_jenkins do
  (中略)
  gem 'spring'
  gem 'spring-commands-rspec'

bundle します。

bundle
Installing spring 1.7.2
Installing spring-commands-rspec 1.0.4

binstub を作成します。

> bundle exec spring binstub --all
* bin/rake: spring inserted
* bin/rspec: generated with spring
* bin/rails: spring inserted

Guardfile のテスト呼び出しを binstub に変更します。

guard :rspec, cmd: "bin/rspec", all_after_pass: false, all_on_start: false do

テストを一つ実行してみましたが、かなり高速化されています。

helper の修正

これまでネストしたヘルパは以下のように作成していました。

module Admins::SessionsHelper
  (中身)
end

これだと autoload で失敗し、読み込んでくれませんでした。いろいろと検索し、以下のように書き換えたらうまくいったので、ヘルパを全て書き換えました。定型の置き換え処理なので、vim のマクロで該当ファイルを一括編集することで、この問題は解決しました。

module Admins
  module SessionsHelper
    (中身)
  end
end

Strong Parameters の追加

attr_accessible がなくなった変わりに、controller に strong_parameters を設定しました。controller に設定した場合、ビューから変更されないパラメータは入れないのですが、まずはテストを通すために、attr_accessible に設定されたいたパラメータを全て permit しています。バージョンが上げ切ったら、変更されたくない属性は削る予定です。パラメータ全部を移行するため、vim のマクロでかなり手間を減らすことができました。

fixtures の修正

fixtures の読み込みで以下の警告が出ていました。

/opt/webcitc/vendor/bundle/ruby/2.2.0/gems/activerecord-4.0.13/lib/active_record/fixtures.rb:570: warning : Return nil in #<=> if the comparison is inappropriate or avoid such comparison.

これは私のプログラムではなく、fixutres の読み込み部分でエラーになっています。fixtures の読み込みの該当部分を確認してみます。

          # interpolate the fixture label
          row.each do |key, value|
            row[key] = label if value == "$LABEL"
          end

データ部分に $LABEL と書かれていると、その部分が yml のキーに差し替えられるようです。ただ、value が nil になっていると、今後エラーになるとのことです。該当する fixutres を見ると、確かに空の属性はキーだけが書いてありました。これを全て消してみたら、警告が出なくなりました。

また、時刻に関する属性についても同じ警告が出ていました。確認すると

  date_from: 2013-06-02 09:00:00

のようになっている部分で出ているようです。この部分を

  date_from: "2013-06-02 09:00:00"

と引用符で括ってあげると警告がでなくなりました。

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

finder API の修正

かなり古いコードや業者が書いたコードに finder API を使ったものが残っていました。これを全て scope のものに修正しました。

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

secret_key_base への変更

secret_token の代わりに、secret_key_base に変更しました。戻ることはないので、4.1 になったら、secret_token は消してしまいます。

Rails 4.0からActiveSupport::KeyGeneratorが導入され、署名付きcookiesの生成と照合などに使われるようになりました。Rails 3.xで生成された既存の署名付きcookiesは、既存のsecret_tokenはそのままにしてsecret_key_baseを新しく追加することで透過的にアップグレードされます。

confirm の修正

link_to の confirm はかなり多く使っているので、これも vim のマクロで一括編集してしまいます。

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

懸念事項

とりあえず、model のテスト、コントローラのテストについては、deprecation を全て潰しましたが、懸念となるのは HTTP PATCH に関する部分です。これは、feature spec でないと確認できませんが、今回は省いています。とりあえず、手元の MacBook で動作するようになってから、直接確認してみようと思います。

Rails 4では、config/routes.rbでRESTfulなリソースが宣言されたときに、更新用の主要なHTTP verbとしてPATCHが使われるようになりました。updateアクションは従来どおり利用でき、PUTリクエストは今後もupdateアクションにルーティングされます。標準的なRESTfulのみを使っている場合、これに関する変更は不要です。 ただし、form_forを用いてリソースを更新しており、PUT HTTPメソッドを使うカスタムルーティングと連動しているのであれば、変更が必要です。

おわりに

とりあえず、上の対応をしたところでのテスト結果です。Ruby のバージョンが変わっていないので、速度は 3.2 とほとんど同じでした。ただ、spring が動いているので、一つずつファイルのテストは圧倒的に早くなっていて、対応が楽になりました。

Finished in 11 minutes 15 seconds (files took 6.03 seconds to load)
7719 examples, 0 failures, 98 pending

Coverage report generated for RSpec to /opt/webcitc/coverage. 23460 / 38104 LOC (61.57%) covered.

gem の推移はこんな感じになりました。

gem_name ver3.2 ver4.0 changed
actionmailer 3.2.22.5 4.0.13
actionpack 3.2.22.5 4.0.13
activemodel 3.2.22.5 4.0.13
activerecord 3.2.22.5 4.0.13
activeresource 3.2.22.5 1.0.4
activesupport 3.2.22.5 4.0.13
arel 3.0.3 4.0.2
bcrypt 3.1.16 3.1.16 =
bcrypt-ruby 3.1.5 -
better_errors 2.9.1 2.9.1 =
binding_of_caller 0.8.0 0.8.0 =
brakeman 4.4.0 4.4.0 =
builder 3.0.4 3.1.4
choice 0.2.0 0.2.0 =
ci_reporter 2.0.0 2.0.0 =
coderay 1.1.3 1.1.3 =
coffee-rails 3.2.2 4.2.2
coffee-script 2.4.1 2.4.1 =
coffee-script-source 1.12.2 1.12.2 =
concurrent-ruby 1.1.7 1.1.7 =
database_cleaner 1.8.5 1.8.5 =
debug_inspector 0.0.3 0.0.3 =
devise 2.2.8 3.5.10
devise-encryptable 0.2.0 0.2.0 =
devise_ldap_authenticatable 0.7.0 0.8.7
diff-lcs 1.4.4 1.4.4 =
docile 1.3.4 1.3.4 =
dotenv 2.7.6 2.7.6 =
erubi 1.10.0 1.10.0 =
erubis 2.7.0 2.7.0 =
execjs 2.7.0 2.7.0 =
factory_bot 4.11.1 4.11.1 =
factory_bot_rails 4.11.1 4.11.1 =
ffi 1.12.2 1.12.2 =
formatador 0.2.5 0.2.5 =
guard 2.15.1 2.15.1 =
guard-compat 1.2.1 1.2.1 =
guard-rspec 4.7.3 4.7.3 =
haml 4.0.7 4.0.7 =
haml-rails 0.4 1.0.0
hike 1.2.3 -
hpricot 0.8.6 0.8.6 =
html2haml 2.2.0 +
i18n 0.9.5 0.9.5 =
interception 0.5 0.5 =
journey 1.0.4 -
jquery-rails 3.1.5 3.1.5 =
json 1.8.6 2.5.1
kaminari 0.17.0 0.17.0 =
listen 3.0.8 3.0.8 =
lumberjack 1.0.13 1.0.13 =
mail 2.5.5 2.7.1
method_source 0.9.2 0.9.2 =
mini_mime 1.0.2 +
mime-types 1.25.1 -
mini_portile2 2.4.0 2.4.0 =
minitest 4.7.5 +
multi_json 1.15.0 1.15.0 =
nenv 0.3.0 0.3.0 =
net-ldap 0.3.1 0.17.0
nokogiri 1.9.1 1.9.1 =
notiffany 0.1.3 0.1.3 =
orm_adapter 0.5.0 0.5.0 =
pg 0.20.0 0.20.0 =
polyglot 0.3.5 -
power_assert 1.2.0 1.2.0 =
pry 0.12.2 0.12.2 =
pry-doc 1.1.0 1.1.0 =
pry-rails 0.3.9 0.3.9 =
pry-rescue 1.5.2 1.5.2 =
public_suffix 3.1.1 3.1.1 =
puma 3.12.6 3.12.6 =
rack 1.4.7 1.5.5
rack-cache 1.9.0 1.9.0 =
rack-ssl 1.3.4 -
rack-test 0.6.3 0.6.3 =
rails 3.2.22.5 4.0.13
rails-erd 1.5.2 1.5.2 =
railties 3.2.22.5 4.0.13
rake 13.0.3 13.0.3 =
rb-fsevent 0.10.4 0.10.4 =
rb-inotify 0.10.1 0.10.1 =
rb-readline 0.5.5 0.5.5 =
rdoc 3.12.2 5.1.0
redcarpet 3.5.1 3.5.1 =
responders 1.1.2 +
rspec 3.9.0 3.9.0 =
rspec-core 3.9.3 3.9.3 =
rspec-expectations 3.9.4 3.9.4 =
rspec-mocks 3.9.1 3.9.1 =
rspec-rails 3.9.1 3.9.1 =
rspec-support 3.9.4 3.9.4 =
ruby-graphviz 1.2.4 1.2.4 =
sass 3.7.4 3.15.0
sass 3.7.4 +
sass-listen 4.0.0 4.0.0 =
sass-rails 3.2.6 6.0.0
sassc 2.4.0 +
sassc-rails 2.1.2 +
sexp_processor 4.15.1 +
shellany 0.0.1 0.0.1 =
simplecov 0.17.1 0.17.1 =
simplecov-html 0.10.2 0.10.2 =
simplecov-rcov 0.2.3 0.2.3 =
spring 1.7.2 +
spring-commands-rspec 1.0.4 +
sprockets 2.2.3 3.7.2
sprockets-rails 2.3.3 +
test-unit 3.3.7 3.3.7 =
thor 0.20.3 0.20.3 =
thread_safe 0.3.6 +
tilt 1.4.1 2.0.10
treetop 1.4.15 -
tzinfo 0.3.58 0.3.58 =
uglifier 4.2.0 4.2.0 =
uniform_notifier 1.11.0 1.11.0 =
warden 1.2.7 1.2.7 =
yard 0.9.25 0.9.25 =
yard-activerecord 0.0.16 0.0.16 =

hkob.hatenablog.com