Rails6.1のままRuby3.0からRuby3.2にアップグレードしました

こんにちは!
はじめまして。ウーオのソフトウェアエンジニアの毛利(@morieeeenyo)です。6月に入社しました。
初回なので簡単に自己紹介させていただければと思います。
1996年、広島県生まれ。3歳〜18歳まで岡山で育った生粋の瀬戸内っ子です。
営業やバックオフィスなどエンジニア以外の職種を経験してからエンジニアになり、 DX支援を行う会社で教育・人材領域を中心にWebアプリの新規開発をしたり、グロースフェーズの社内ベンチャーに参画してスクラムによるアジャイル開発をしたりしていました。地元瀬戸内の企業で働けること、エンジニアがビジネスチームやエンドユーザーと接しながら裁量高く働ける環境に魅力を感じ入社しました。
これからよろしくお願いいたします!
今回の記事ではウーオのRubyアップグレードについて書かせていただければと思います。
Rubyアップグレードを行った背景
Rubyのアップグレードを行なった背景としては、インフラのアップグレードに伴いRubyのバージョンも一緒にあげよう!となった形になります。アップグレード先のRubyのバージョンとしてはYJITが使える最低限のバージョンということで3.2を選びました。RailsについてはRails7ではWebpackerが廃止されるなど大きく変更が必要そうであったことを鑑みて今回のアップグレード作業のスコープからは外し、今後段階的にアップグレードしていくことにしました。
なお、Rubyアップグレードを任された当時、私は入社2週間も経っていない頃。まだキャッチアップすべきことだらけで右も左もわからない中、突然メンションが飛んできました。

とんでもないメンションが飛んできたぞ・・・と面食らったのをよく覚えています。 正直Rubyのアップグレードは他の人のPRをレビューしたことがある程度で、自分でゼロからやったことは無かったのですが、ドメイン知識に依らない技術的な課題解決は入社まもない自分にとってチームに貢献する数少ないチャンスだ!と思って手を挙げてみることにしました。
Rubyアップグレードの進め方
ウーオのプロダクトチームでは「開発・プロダクト品質向上タイム」という時間を2週間に一度設けています。 これは機能開発以外の不具合の修正やリファクタリング、社内ドキュメントの整備など緊急ではないが重要なことに使う時間で、定期的に枠を設けることによって強制的に品質向上に時間を使えるようにするために実施しています。 今回のRubyアップグレードもこの時間を活用して進めました。
丸一日時間を使えるとはいえ集中して時間を使えるのは2週間に一度しかないため限られた時間でなるべくリリースReadyな状態を作ることを意識して進めました。
具体的には
- アプリが正しく動作すること
- デザイン崩れを起こしていないこと
- CIが通ること
- ローカルの開発に支障ないこと
を優先的に達成できるようにし、gemやnpm packageのバージョンに起因するWARNINGの解消などは後に回すようにしました。
具体的な作業内容
ここからはRubyをアップグレードするために具体的に行った作業を記載していきます。
Ruby3.1へのアップグレード
Ruby3.2にアップグレードするにあたり、3.0→3.1→3.2と段階的にアップグレードするようにしました。具体的にはmasterブランチからRuby3.1アップグレード用のブランチを切り、そこからさらに3.2にアップグレードするためのブランチを切るという形にしました。これにより、修正内容がRuby3.1へのアップグレードによるものなのか3.2へのアップグレードによるものなのか特定しやすくなります。
1. Dockerのビルドを通せるようにする
ウーオではバックエンドをDockerを用いて開発しています。
そのため、まずはDockerで使うRubyのイメージを変更してビルドを通すところから始めました。
- FROM ruby:3.0.3-alpine3.14 + FROM ruby:3.1.6-alpine3.20
Dockerで使えるRubyイメージはDockerのOfficial Imagesのサイトから探しました。
イメージを変更したら以下を実行します。
docker compose build --no-cache
するとビルド時のコマンドのどこかしらでエラーが発生するのでこれをひたすら直していきます。
今回のアップグレードでは具体的には以下の2点を修正しました。
- Node.jsのバージョンアップ
- python2→python3への変更
Node.jsのバージョンアップを行なったのは当時採用していたNode.jsのバージョンがalpine3.20では使えなかったためです。またNode.jsをアップグレードする際にpython2→python3へのアップグレードが必要になったので併せてアップグレードしました。
使用するNode.jsのバージョンは他のパッケージとの依存関係的に20.13.1を使うのが都合がよさそうだったので、yarn installを通すのに苦戦しない限りはそれを使おうと考えました。
Node.jsのバージョン変更の結果として、yarn installでWebpackerの依存関係のエラーが出たので Webpackerのバージョンアップを行いました。メジャーバージョンを変更しないのであれば大きくは挙動には影響しないはず、という考えから当時使用していた5系の最新版(5.4.4)にアップグレードしました。
ここまで対応した段階でDockerのビルドが通りました。
2. ローカルで動作確認
Dockerのビルドが通った後、軽くローカルで動作確認を行いました。
Webpackerをアップグレードした影響でCSSが正しく当たらなくなったので調査しました。
具体的にはアプリケーションコンテナの中で以下のコマンドを実行し、出てきたエラーを解消していきました。
bin/webpack-dev-server
するとSCSSファイルのインポートでエラーが発生していることが確認でき、修正を実施しました。
3. RuboCopのTargetRubyVersionを上げる
ローカルで問題なく動作してそうなことを確認したので、次にCIを通します。
CIを通すためにまずはRuboCopのTagetRubyVersionを上げました。
.rubocop.yml
- TargetRubyVersion: 3.0.3 + TargetRubyVersion: 3.1.6
RuboCopでは以下の二つのルールに引っかかりました。
- Style/HashSyntax
- Layout/MultilineOperationIndentation
- 一つの処理が複数行にまたがる場合にインデントを揃えてくれます
これらはいずれもauto-correctableとのことで、作業が複雑にならずホッとしました。
4. RSpecを通す
ウーオのCIではRuboCopの他にRSpecも実行しています。
Ruby 3.1.6へのアップグレードでは特にRSpecでのエラーは発生しませんでした。
Ruby3.2へのアップグレード
3.1で動作やCIの実行結果に問題ないことを確認したのち、3.2へとアップグレードしました。
3.2でも1~4の手順を行います。
3.1へのアップグレードとの違いとして、RuboCopのTargetRubyVersionに3.2.4を指定するためにrubocop gemのアップデートが必要になったのでアップデートしました。
また、Ruby3.2のscopeでキーワード引数の扱いの変更され、scopeでキーワード引数を使うとArgumentErrorが出るようになってしまいました。
具体的には以下のようなスコープを実行すると wrong number of arguments (given 1, expected 0; required keywords:role) (ArgumentError) というエラーになりました。
class User scope :with_role, ->(role:) { where(role: role) } end User.with_role(role: :admin) =>wrong number of arguments (given 1, expected 0; required keywords:role) (ArgumentError)
そのため以下のようにキーワード引数を使わない実装に変更しました。
class User scope :with_role, ->(role) { where(role: role) } end User.with_role(:admin)
RSpecでこれが原因で多くのエラーが発生したのですが、こちらのissue等を見るとこのエラーはどうもRuby3.2 + Rails6.1.7の組み合わせで起こり、Railsをアップグレードしないと解消されなさそうでした。そのため、キーワード引数を使っているscopeをgrepしては修正して、を繰り返しました。(これは結構骨が折れました…あとテストコードをちゃんと書いてて良かったと思いました)。
grepする際は 以下のコマンドでリポジトリを検索しました。
git grep -E "scope :.*:.*(\{|do)"
5. リグレッションテスト
Ruby 3.2でCIが通ったら実際にデプロイします。
Rubyアップグレードはアプリ全体に影響があるため、QAエンジニアによるリグレッションテストも行いました。ウーオではリグレッションテストの項目をNotionのテンプレートを用いて管理しており、変更の影響範囲に応じて誰でもリグレッションテストを実施できる仕組みを構築しています。
6. 無事にリリース
リグレッションテストで発見したバグの修正完了後、無事リリースを迎えることができました。
まとめ
今回はウーオのRubyアップグレード対応についてまとめました。
実装開始から1ヶ月でリリースを迎えることができましたが、機能開発と並行して進めていたことを考えるとスピード感を持って対応できたのではないかと思います。影響範囲が広く開発着手時は不安な点もありましたが、CIによる自動テストやリグレッションテストのおかげで安心してリリースを迎えることができました。
ウーオのプロダクトチームでは「技を磨き、持続可能なものづくりを追求しよう」というValueを掲げており、今後も持続可能な開発のためにテストの拡充やライブラリのアップデートを積極的に行っていきたいと思います 💪
※プロダクトチームのValueについては以下の記事をご覧ください! tech-uuuo.hatenablog.jp
最後までご覧いただきありがとうございました!
ウーオでは水産流通を革新するため、プロダクトを通じてあらゆるアプローチをしています。ウーオの事業やプロダクト開発にご興味がある方は、ぜひ下記を覗いてみてください。👇
水産流通を革新する自社プロダクトを開発!サーバーサイドエンジニアを募集! - 株式会社ウーオのWebエンジニアの採用 - Wantedly
水産の新しいインフラを作る、フロントエンドエンジニア募集! - 株式会社ウーオのWebエンジニアの採用 - Wantedly
水産業の課題解決をユーザー目線のUI/UXでリードするデザイナー募集! - 株式会社ウーオのUI/UXデザイナーの採用 - Wantedly
Flutterで水産DXアプリ開発!iOS/Androidエンジニア募集! - 株式会社ウーオのモバイルエンジニアの採用 - Wantedly
1日2時間〜遠隔での対応歓迎!水産流通DXを実現するアプリのテスター募集! - 株式会社ウーオのQAエンジニアの採用 - Wantedly