RailsアプリをRuby 2.7.0で動かして分かったこと
濱田 裕太
はじめに (背景)
昨年のクリスマスにRuby 2.7.0がリリースされました。
Ruby 2.7は今年リリース予定のRuby 3への移行を見据えたバージョンであり、多くの新機能や変更点があります。そこで、弊社が企画制作する『Babyプラス』のRailsアプリをRuby 2.6.5 -> 2.7.0に上げて動かしてみたところ、約1,000件のテストケース実行に対して6件のエラーと2,700件ほどのワーニングが発生しました。この結果の分析によりRuby 2.7移行について傾向と対策が見えてきたので、現時点 (2020/01/08) で分かったことを共有します。
結論 (Ruby2.7移行についての傾向と対策)
- 傾向として、多くのgemがRuby 2.7.0からワーニングとなる言語仕様変更の影響を受ける
- 具体的には、ブロック無しProc.new/proc/lambdaおよびキーワード引数 (kwargs) 分離に関するワーニングが多く発生する
- 特にキーワード引数 (kwargs) 分離の影響が大きく、2020/01/08時点ではrailsなどメジャーなgemも対応完了していない
- 対策として、該当gemに対して以下を実施すると良さそう
- 対策 1: 最新版に更新する (Ruby 2.7.0に対応しているgem)
- e.g.) mysql2 (0.5.3)
- e.g.) json (2.3.0)
- e.g.) tzinfo (1.2.6), tzinfo (2.0.1)
- e.g.) faraday (0.17.3), faraday (1.0.0)
- e.g.) bullet (6.1.0)
- 対策2: 対応するまで待つ or プルリクを出す (Ruby 2.7.0に対応していないgem)
- e.g.)
rails (5.2.4.1), rails (6.0.2.1)- koicさんのエントリ (1/8) より、5.2系にはバックポートされないことが分かった
- e.g.) jbuilder (2.9.1)
- e.g.)
- 対策3: 別手段に置き換える (存在が非推奨になっているgem)
- e.g.) paperclip -> activestorage (参考リンク)
- e.g.) rails-controller-testing -> request spec (参考リンク)
- 対策 1: 最新版に更新する (Ruby 2.7.0に対応しているgem)
詳細
以下、結論に至る過程を具体例を交えて解説します。
(1) テスト実行で発生したエラー・ワーニングのパターン
RailsアプリをRuby 2.6.5 -> 2.7.0に上げた状態でrspecによる約1,000件のテストケースを実行した結果、before (更新前のgem) ではエラーが6件、ワーニングが2,700件ほど発生しました。after (更新後のgem) ではエラーは0件になりましたが、ワーニングが500件ほど発生しました。これらは全て依存gem起因であり、プロダクトコード起因でのエラー・ワーニングは発生しませんでした。
gem名 (before -> after) | 発生パターン | 発生件数 (before) |
発生件数 (after) |
対策案 |
---|---|---|---|---|
mysql2 (0.4.10 -> 0.5.3) | error 1 | 6 | 0 | 対策1 |
error 合計 | 6 | 0 | ||
activerecord (5.2.3 -> 5.2.4.1) | warning1 | 81 | 0 | 対策1 |
activesupport (5.2.3 -> 5.2.4.1) | warning1 | 1,869 | 0 | 対策1 |
faraday (0.17.0 -> 0.17.3) | warning1 | 10 | 0 | 対策1 |
jbuilder (2.9.1) | warning1 | 441 | 441 | 対策2 |
json (2.2.0 -> 2.3.0) | warning2 | 289 | 0 | 対策1 |
tzinfo (1.2.5 -> 1.2.6) | warning2 | 2 | 0 | 対策1 |
actionpack (5.2.3 -> 5.2.4.1) | warning3 | 6 | 6 | 対策2 |
actionview (5.2.3 -> 5.2.4.1) | warning3 | 2 | 2 | 対策2 |
activemodel (5.2.3 -> 5.2.4.1) | warning3 | 3 | 3 | 対策2 |
activerecord (5.2.3 -> 5.2.4.1) | warning3 | 7 | 7 | 対策2 |
activesupport (5.2.3 -> 5.2.4.1) | warning3 | 1 | 1 | 対策2 |
bullet (6.0.2 -> 6.1.0) | warning3 | 1 | 0 | 対策1 |
rails-controller-testing (1.0.4) | warning3 | 5 | 5 | 対策3 |
paperclip (6.1.0) | warning4 | 15 | 15 | 対策3 |
rb-inotify (0.10.0 -> 0.10.1) | warning5 | 37 | 0 | 対策1 |
warning 合計 | 2,769 | 491 |
(2) 発生したエラー・ワーニングのパターン分類
発生したエラー・ワーニングをパターン分類すると以下の結果になりました。warning1~3がRuby 2.7.0からワーニングとなる言語仕様変更に関するものであり、発生件数の大半を占めています。このうちwarning1がブロック無しProc.new/proc/lambdaで、warning2, 3がキーワード引数 (kwargs) 分離に関するワーニングです。
発生パターン | メッセージ (補足説明) |
---|---|
error1 | NoMethodError: undefined method `new' for BigDecimal:Class (decimal型カラムが存在するDBスキーマのレコードインスタンス取得時に発生する) (これはRuby 2.6 (bigdecimal 1.4.0) ではワーニングだったBigDecimalの仕様変更がRuby 2.7 (bigdecimal 2.0.0) からはエラーとなるためである) |
warning1 | warning: Capturing the given block using Proc.new is deprecated; use `&block' instead |
warning2 | warning: Using the last argument as keyword parameters is deprecated (該当メソッドがNative Extension (C言語層) で定義されている場合はwarning 3でなくこのパターンになる) |
warning3 | warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call warning: The called method `{該当メソッド名}' is defined here |
warning4 | warning: URI.escape is obsolete |
warning5 | warning: rb_safe_level will be removed in Ruby 3.0 |
(3) エラー・ワーニングへの対策案
前述のエラー・ワーニングへの対策案をまとめると以下になります。Ruby 2.7.0に対応しているgemは最新版に更新(対策1)し、Ruby 2.7.0に対応していないgemは対応するまで待つ or プルリクを出す(対策2)か、別手段に置き換える(対策3)のが良さそうです。
対策案 | 内容 |
---|---|
対策1 | 最新版に更新する (Ruby 2.7.0に対応しているgem) - e.g.) mysql2 (0.5.3) - e.g.) json (2.3.0) - e.g.) tzinfo (1.2.6), tzinfo (2.0.1) - e.g.) faraday (0.17.3), faraday (1.0.0) - e.g.) bullet (6.1.0) |
対策2 | 対応するまで待つ or プルリクを出す (Ruby 2.7.0に対応していないgem) - e.g.) (koicさんのエントリ (1/8) より、5.2系にはバックポートされないことが分かった) - e.g.) jbuilder (2.9.1) |
対策3 | 別手段に置き換える (存在が非推奨になっているgem) - e.g.) paperclip -> activestorage (参考リンク) - e.g.) rails-controller-testing -> request spec (参考リンク) |
なお、実行時に -W:no-deprecated オプションで非推奨ワーニングを抑制する方法もありますが、Railsバージョンアップ時の非推奨ワーニングなどを見逃す可能性があるため、開発時やテスト実行時にはやらない方が良いかも知れません。
(おまけ) テスト実行時間の比較 (Ruby 2.6.5 vs 2.7.0)
rspecによる約1,000件のテストケース実行時間は、Ruby 2.6.5 vs 2.7.0でほとんど変わりませんでした。
# ruby 2.6.5
Finished in 1 minute 9.84 seconds (files took 2.56 seconds to load)
# ruby 2.7.0
Finished in 1 minute 10.4 seconds (files took 2.86 seconds to load)
しかし、Ruby 2.7.0では様々なパフォーマンス改善が成されているようなので、本番運用では何らかのパフォーマンス向上が得られるかも知れません。これはまたの機会に検証してみたいと思います。
おわりに
Ruby 2.7.0がリリースされたので、弊社が企画制作する『Babyプラス』のRailsアプリをRuby 2.7.0で動かしてみて現時点 (2020/01/08) で分かったことを共有しました。本エントリがRuby 2.7を利用する上で何かのお役に立てれば幸いです。
今回Ruby 2.7やrailsなどのgemについて色々調べたり手を動かしたりしたことで、プログラミング言語やライブラリを開発/保守している方々への敬意を強く覚えました。時にはRubyコミッタとRailsコミッタが連携して双方にとってより良い改善策を模索するやりとりなども目の当たりにし、頭が下がる思いを抱きました。プログラミング言語やライブラリは、云うなれば「ITエンジニアという世界中のヘビーユーザーに毎日利用されているプロダクト」なのだと再認識した次第です。それらを利用して日々開発ができることに改めて感謝です。