Rails アプリケーションの Ruby バージョンを 2.2.3 から 2.6.2 へアップグレードした話
Rails アプリケーションの Ruby バージョンを 2.2.3 から 2.6.2 まで上げました。しかし、今回の対応は、主にアプリケーションが利用する gem のバージョンアップグレードとなってしまいました。Rails アプリケーションで利用する Ruby バージョンを大きくアップグレードする際の調査の進め方などが少しでも参考になれば幸いです。
背景
Ruby 2.2 は2018年3月31日をもってサポートが終了しています。
— Support of Ruby 2.2 has ended
しかし、対象となったアプリケーションはテストコードが書かれておらず、バージョンアップを行なってもアプリケーションの動作担保が難しい状態でした。
一方で、機能開発を止めることも難しかったため、機能追加を行うたびにテストコードを少しずつ増やしてきました。そして、ようやく最低限のテストコードが揃ったと判断し、今回の Ruby のバージョンアップに踏み切りました。
TL;DR
ruby と、依存する 最低限の gem 10個をアップデートしました。
- ruby を 2.2.3 -> 2.6.2 にアップデート
- rails を 4.2.6 -> 4.2.11.1 にアップデート
- delayed_job を 4.1.2 -> 4.1.5 にアップデート
- fog を 1.33.0 -> 1.41.0 にアップデート
- therubyracer を 0.12.2 -> 0.12.3 にアップデート
- 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 を立ち上げる
まずは、ローカル環境で ruby のバージョンをあげ rails server
が立ち上げるところまでを目指します。以下、エラーの発生した gem と、その原因の調査結果、および対応です。
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
原因
- ruby 2.5.0-rc1 で psych のアップデートが行われた
- psych v3.0.0.beta2 で
yaml_as
が削除された
対応
- delayed_job をアプリケーションが依存する 4.1.2 から最新版である 4.1.5 にアップデート
- delayed_job は 4.1.4 で
yaml_as
からyaml_tag
に変更されたため
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 をアプリケーションが依存する 1.33.0 から最新版である 1.41.0 にアップデート
- fog は 1.35.0 より fog-xenserver に依存するように修正されている
- fog-xenserver は 0.3.0 で Ruby 2.4 以上であれば前述の XMLRPC gem を使うように修正
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.2 から最新版である 0.12.3 にアップデート
- therubyracer では Integer class に 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 をアプリケーションが依存する 4.2.6 から最新版である 4.2.11.1 にアップデート
- Rails 5 向けに追加された対応を 4 向けにバックポート。Rails 4.2.8-rc1 で追加された
簡単な動作を確認をする
ここまでで 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.4 から最新版である 5.0.7 にアップデート
- sass-rails も 5.0.6 で対応
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! を利用することが推奨されている。今回の修正範囲外とするが早めに対応したい。
— 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 をアプリケーションが依存する 0.1.1 から最新版である 1.1.3 にアップデート
- 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 となっていなかった
- Syntax error on Ruby 2.5.0 · Issue #4736 · plataformatec/devise
- Bug #505: 1.upto 2 {|i| p i } - Ruby trunk - Ruby Issue Tracking System
- Bug #13547: [].delete 1 { ‘NG’ } - Ruby trunk - Ruby Issue Tracking System
- Bug #14023: SyntaxError on array argument and block - Ruby trunk - Ruby Issue Tracking System
対応
- devise をアプリケーションが依存する 3.5.10 から最新版である 4.6.2 にアップデート
- devise は 4.4.0 で修正された
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.5.5 から最新版である 1.7.5 にアップデート
- devise_invitable 1.6.0 から devise 4 に対応した
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 って呼び方はよくないんじゃないかという発言に起因すると思われる
対応
- rubocop をアプリケーションが依存する 0.60.0 から最新版である 0.67.2 にアップデート
- psych もこの流れを受け名前を変更し、 3.1.0 で対応が取り込まれる
- ruby では 2.6.0 で psych の version アップデートが行われる
- rubocop では 0.61.0 で対応されている
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 [email protected]: undefined method `<' for nil:NilClass (SSHKit::Runner::ExecuteError)
原因
—
対応
- capistrano をアプリケーションが依存する 3.4.0 から最新版である 3.11.0 にアップデート
- sshkit 1.8.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 達も、アップデートしていきたいと思います。