RailsアプリをRuby 2.7.0で動かして分かったこと

濱田 裕太
183

はじめに (背景)

昨年のクリスマスに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移行についての傾向と対策)

詳細

以下、結論に至る過程を具体例を交えて解説します。

(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.) rails (5.2.4.1), rails (6.0.2.1)
(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エンジニアという世界中のヘビーユーザーに毎日利用されているプロダクト」なのだと再認識した次第です。それらを利用して日々開発ができることに改めて感謝です。

参考リンク