Ruby 2.2.3 で動いている Rails アプリケーションの Ruby バージョンを 2.6.2 まで上げました。対応の多くがアプリケーションが依存する gem によってしまうので、全ての対応が適用できる訳ではありませんが、少しでも参考になれば幸いです。
背景
Ruby 2.2 は2018年3月31日をもってサポートが終了しています。
しかし、対象となったアプリケーションはテストコードが書かれておらず、バージョンアップを行なってもアプリケーションの動作担保が難しい状態でした。
一方で、機能開発を止めることも難しかったため、機能追加を行うたびにテストコードを少しずつ増やしてきました。そして、ようやく最低限のテストコードが揃ったと判断し、今回の Ruby のバージョンアップに踏み切りました。
TL;DR
ruby と、依存する 最低限の gem 10個をアップデートしました。
- ruby を 2.2.3 -> 2.6.2 にアップデート
- delayed_job を 4.1.2 -> 4.1.5 にアップデート
- fog を 1.33.0 -> 1.41.0 にアップデート
- therubyracer を 0.12.2 -> 0.12.3 にアップデート
- rails を 4.2.6 -> 4.2.11.1 にアップデート
- sass-rails を 5.0.4 -> 5.0.7 にアップデート
- activerecord-session_store を 0.1.1 -> 1.1.3 にアップデート
- devise を 3.5.10 -> 4.6.2 にアップデート
- devise_invitable を 1.5.5 -> 1.7.5 にアップデート
- capistrano を 3.4.0 -> 3.11.0 にアップデート
- rubocop を 0.60.0 -> 0.62.0 にアップデート
rails server を立ち上げる
まずはローカル環境で rails server が立ち上げることを目指します。以下、発生したエラーとその原因、対応です。
delayed_job
ERROR メッセージ
Bundler::GemRequireError: There was an error while trying to load the gem 'delayed_job_active_record'.
Gem Load Error is: undefined method `yaml_as' for ActiveRecord::Base:Class
原因
- psych v3.0.0.beta2 で
yaml_as
が削除された - ruby では 2.5.0-rc1 で psych のアップデートが行われた
対応
- delayed_job は 4.1.4 で
yaml_as
からyaml_tag
に変更された - アプリケーションが依存している delayed_job は 4.1.2
- delayed_job を最新版 (4.1.5) にアップデートする
fog
ERROR メッセージ
LoadError: cannot load such file -- xmlrpc/client
<略>
/Users/tetsuya/dev/app_name/vendor/bundle/ruby/2.6.0/gems/fog-1.33.0/lib/fog/xenserver/core.rb:23:in `<class:Connection>'
/Users/tetsuya/dev/app_name/vendor/bundle/ruby/2.6.0/gems/fog-1.33.0/lib/fog/xenserver/core.rb:22:in `<module:XenServer>'
/Users/tetsuya/dev/app_name/vendor/bundle/ruby/2.6.0/gems/fog-1.33.0/lib/fog/xenserver/core.rb:5:in `<module:Fog>'
/Users/tetsuya/dev/app_name/vendor/bundle/ruby/2.6.0/gems/fog-1.33.0/lib/fog/xenserver/core.rb:4:in `<top (required)>'
原因
- Ruby 2.4.0-preview2 から XMLRPC が gem として提供されるようになった
対応
- fog-xenserver は 0.3.0 で Ruby 2.4 以上であれば前述の gem を使うように修正
- fog は 1.35.0 より fog-xenserver に依存するように修正されている
- アプリケーションが依存している fog は 1.33.0
- fog を最新版 (1.41.0) にアップデートする
therubyracer
ERROR メッセージ
Bundler::GemRequireError: There was an error while trying to load the gem 'therubyracer'.
Gem Load Error is: wrong argument type Class (expected Module)
原因
- Ruby 2.4.0-rc1 で Fixnum と Bignum が Integer に統一されたため
対応
- therubyracer も 0.12.3 で対応した
- アプリケーションが依存している therubyracer は 0.12.2
- therubyracer を最新版 (0.12.3) にアップデートする
rails
ERROR メッセージ
SystemStackError: stack level too deep
/root/repo/vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.6/lib/active_support/core_ext/numeric/conversions.rb:131:in `block (2 levels) in <class:Numeric>'
原因
- Ruby 2.4.0-rc1 で Fixnum と Bignum が Integer に統一されたため
対応
- Rails 5 向けに追加された対応を 4 向けにバックポート。Rails 4.2.8-rc1 で追加された。
- アプリケーションが依存している rails は 4.2.6
- rails を最新版 (4.2.11.1) にアップデートする
簡単な動作を確認をする
ここまでで rails server が立ち上がりました 動作を確認しながら WARN/ERROR メッセージに対応していきます。
sass-rails
WARN メッセージ
DEPRECATION WARNING: Sprockets method `register_engine` is deprecated.
Please register a mime type using `register_mime_type` then
use `register_compressor` or `register_transformer`.
https://github.com/rails/sprockets/blob/master/guides/extending_sprockets.md#supporting-all-versions-of-sprockets-in-processors
(called from block (2 levels) in <class:Railtie> at /root/repo/vendor/bundle/ruby/2.6.0/gems/sass-rails-5.0.4/lib/sass/rails/railtie.rb:57)
DEPRECATION WARNING: Sprockets method `register_engine` is deprecated.
Please register a mime type using `register_mime_type` then
use `register_compressor` or `register_transformer`.
https://github.com/rails/sprockets/blob/master/guides/extending_sprockets.md#supporting-all-versions-of-sprockets-in-processors
(called from block (2 levels) in <class:Railtie> at /root/repo/vendor/bundle/ruby/2.6.0/gems/sass-rails-5.0.4/lib/sass/rails/railtie.rb:58)
no_proxy is unsupported
原因
- sprockets 3.7.0 で
register_engine
が非推奨になったため - rails のバージョンを上げたタイミングで依存する sprockets も 3.5.2 から 3.7.2 に上がった
対応
- sass-rails も 5.0.6 で対応
- アプリケーションが依存している sass-rails は 5.0.4
- sass-rails を最新版 (5.0.7) にアップデートする
bundle update
は完了するが、以下のメッセージが表示される。
Ruby Sass is deprecated and will be unmaintained as of 26 March 2019.
sass-rails のメンテナンスが2019年3月26日をもって終了した。今後は、sass/sassc-ruby: Use libsass with Ruby! を利用することが推奨されている。今回の修正範囲外とするが早めに対応したい。
See also: Ruby Sass Has Reached End-Of-Life « Sass Blog
activerecord-session_store
ERROR メッセージ
Thread.exclusive is deprecated, use Thread::Mutex
/Users/tetsuya/dev/app_name/vendor/bundle/ruby/2.6.0/gems/activerecord-session_store-0.1.1/lib/active_record/session_store/session.rb:32:in `find_by_session_id'
/Users/tetsuya/dev/app_name/vendor/bundle/ruby/2.6.0/gems/activerecord-session_store-0.1.1/lib/action_dispatch/session/active_record_store.rb:66:in `block in get_session'
原因
- Ruby 2.3.0-preview2 から
Thread.exclusive
が非推奨になったため
対応
- activerecord-session_store では 1.1.3 で修正されている
- アプリケーションが依存している activerecord-session_store は 0.1.1
- activerecord-session_store を最新版 (1.1.3) にアップデートする
devise
ERROR メッセージ
SyntaxError - syntax error, unexpected '{', expecting keyword_end
...ter only: [:create, :destroy] { request.env["devise.skip_tim...
... ^
/Users/tetsuya/dev/app_name/vendor/bundle/ruby/2.6.0/gems/devise-3.5.10/app/controllers/devise/sessions_controller.rb:5: syntax error, unexpected '}', expecting keyword_end
..."devise.skip_timeout"] = true }
... ^:
devise (3.5.10) app/controllers/devise/sessions_controller.rb:5:in `'
undefined method `unshift' for nil:NilClass excluded from capture: No host specified, no public_key specified, no project_id specified
NoMethodError (undefined method `unshift' for nil:NilClass):
原因
- 本来は syntax error であるが ruby のバージョンによっては ERROR となっていなかった
対応
- devise は 4.4.0 で修正された
- アプリケーションが依存している devise は 3.5.10
- devise を最新版 (4.6.2) にアップデートする
$ bundle update devise
ERROR メッセージ
NoMethodError - undefined method `for' for #<Devise::ParameterSanitizer:0x00007fc999e94890>:
undefined method `user_omniauth_authorize_path' for #<#<Class:0x00007ffa5913a5c8>:0x00007ffa58bae348>
原因
- 上記対応で devise がバージョンアップされた
- devise 4.0.0.rc2 で非推奨となった method が 4.2.0 で削除されたため
対応
- devise_parameter_sanitizer.for(:sign_up)
- devise_parameter_sanitizer.for(:sign_in)
+ devise_parameter_sanitizer.permit(:sign_up)
+ devise_parameter_sanitizer.permit(:sign_in)
- user_omniauth_authorize_path(:facebook)
+ user_facebook_omniauth_authorize_path
devise_invitable
ERROR メッセージ
Traceback (most recent call last):
bin/rails: undefined method `attributes_for' for class `Devise::ParameterSanitizer' (NameError)
原因
- devise 4.0.0.rc1 で
Devise::ParameterSanitizer#attributes_for
が削除されたため
対応
- devise_invitable 1.6.0 から devise 4 に対応した
- アプリケーションが依存している devise_invitable は 1.5.5
- devise_invitable を最新版 (1.7.5) にアップデートする
Rspec や Rubocop などを動かす
ここまででローカル環境での動作確認ができました ここから Rspec や Rubocop などを動かしていきます。
rubocop
ERROR メッセージ
$ bundle exec rubocop
unknown keywords: whitelist_classes, whitelist_symbols
/Users/tetsuya/.rbenv/versions/2.6.2/lib/ruby/2.6.0/psych.rb:328:in `safe_load'
/Users/tetsuya/dev/app_name/vendor/bundle/ruby/2.6.0/gems/rubocop-0.60.0/lib/rubocop/config_loader.rb:185:in `yaml_safe_load'
/Users/tetsuya/dev/app_name/vendor/bundle/ruby/2.6.0/gems/rubocop-0.60.0/lib/rubocop/config_loader.rb:159:in `load_yaml_configuration'
/Users/tetsuya/dev/app_name/vendor/bundle/ruby/2.6.0/gems/rubocop-0.60.0/lib/rubocop/config_loader.rb:40:in `load_file'
/Users/tetsuya/dev/app_name/vendor/bundle/ruby/2.6.0/gems/rubocop-0.60.0/lib/rubocop/config_loader.rb:82:in `configuration_from_file'
/Users/tetsuya/dev/app_name/vendor/bundle/ruby/2.6.0/gems/rubocop-0.60.0/lib/rubocop/config_store.rb:44:in `for'
/Users/tetsuya/dev/app_name/vendor/bundle/ruby/2.6.0/gems/rubocop-0.60.0/lib/rubocop/cli.rb:187:in `apply_default_formatter'
/Users/tetsuya/dev/app_name/vendor/bundle/ruby/2.6.0/gems/rubocop-0.60.0/lib/rubocop/cli.rb:40:in `run'
/Users/tetsuya/dev/app_name/vendor/bundle/ruby/2.6.0/gems/rubocop-0.60.0/exe/rubocop:13:in `block in <top (required)>'
/Users/tetsuya/.rbenv/versions/2.6.2/lib/ruby/2.6.0/benchmark.rb:308:in `realtime'
/Users/tetsuya/dev/app_name/vendor/bundle/ruby/2.6.0/gems/rubocop-0.60.0/exe/rubocop:12:in `<top (required)>'
/Users/tetsuya/dev/app_name/vendor/bundle/ruby/2.6.0/bin/rubocop:23:in `load'
/Users/tetsuya/dev/app_name/vendor/bundle/ruby/2.6.0/bin/rubocop:23:in `<top (required)>'
原因
- 元を辿ると DHH の black/whitelist って呼び方はよくないんじゃないかという発言に起因する
対応
- psych もこの流れを受け名前を変更、 3.1.0 で対応が取り込まれる
- ruby では 2.6.0 で psych の version アップデートが行われる
- rubocop では 0.61.0 で対応されている
- アプリケーションが依存している rubocop は 0.60.0
- rubocop を最新版 (0.67.2) にアップデートする
rubocop-github
ERROR メッセージ
Error: The `Performance/LstripRstrip` cop has been moved to `Style/Strip`
(obsolete configuration found in vendor/bundle/ruby/2.6.0/gems/rubocop-github-0.12.0/config/default.yml, please update it)
原因
- 上記対応で rubocop がバージョンアップされた
- Rubocop 0.63.0 で Style/FlipFlop が Lint/FlipFlop に移動された
対応
- 既に PR は出ている
- merge されるまで、 rubocop 0.62.0 にバージョンを固定する
検証環境に deploy する
CI も通ったので検証環境に deploy 試みます。
sshkit
ERROR メッセージ
/Users/tetsuya/dev/app_name/vendor/bundle/ruby/2.6.0/gems/sshkit-1.7.1/lib/sshkit/runners/parallel.rb:16:in `rescue in block (2 levels) in execute': Exception while executing as devuser@52.197.98.157: undefined method `<' for nil:NilClass (SSHKit::Runner::ExecuteError)
原因
--
対応
-
sshkit 1.8.0 で入っていった対応により、副次的に修正がされている
-
アプリケーションが依存している capistrano は 3.4.0
-
capistrano を最新版 (3.11.0) にアップデートする
capistrano
WARN メッセージ
[Deprecation Notice] Future versions of Capistrano will not load the Git SCM
plugin by default. To silence this deprecation warning, add the following to
your Capfile after `require "capistrano/deploy"`:
require "capistrano/scm/git"
install_plugin Capistrano::SCM::Git
原因
- 上記対応で capistrano がバージョンアップされた
- capstrano 3.7 で
scm
が非推奨となった - それに伴い、WARN メッセージが表示されるようになった
対応
WARN メッセージにある通り、 Capfile
に追記した
+ require "capistrano/scm/git"
+ install_plugin Capistrano::SCM::Git
未解決
WARN メッセージ
/root/repo/vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/object/duplicable.rb:111: warning: BigDecimal.new is deprecated; use BigDecimal() method instead.
最後に
ruby 2.2.3 から 2.6.2 とマイナーバージョンが4つ上がっただけの様に感じましたが、2.2.3 (2015年8月18日) から 2.6.2 (2019年3月13日リリース) の間に実に3年7ヶ月の時間があり、様々なアップデートが行われていたことがわかりました。
Rails の脆弱性対応も気になっていたので、4.2 系の最新版である 4.2.11.1 にアップデートできたのは安心感があります。
Ruby や Rails を使うメリットの一つに、活発なコミュニティと成熟したエコシステムがあると思います。今後も進化し続けるこの言語/フレームワークを使い続けられる様、しっかりとアップデートに追従していきながら、残念ながら今回はバージョンアップを見送ってしまった gem 達も、アップデートしていきたいと思います。