SMARTCAMP Engineer Blog

スマートキャンプ株式会社(SMARTCAMP Co., Ltd.)のエンジニアブログです。業務で取り入れた新しい技術や試行錯誤を知見として共有していきます。

Rails7.1へバージョンアップした話

はじめに

こんにちは!スマートキャンプ開発エンジニアの末吉(だいきち)です。

今回は、BALES CLOUDにてRailsとRubyのバージョンアップを行いましたので、 そちらについてお話ししたいと思います!

バージョン詳細

具体的なバージョンについては、以下の通りです。

  • Ruby on Rails: 7.0.2 -> 7.1.3.2
  • Ruby: 3.0.4 -> 3.3.0

作業内容

今回行った作業の概要は以下の通りです。

Railsバージョンアップ

  1. 5.2 ~ 7.0までで変更されたデフォルト値を確認 。(詳細は大変だったこと&ハマったことを参照)
  2. Gemfile > railsのバージョンをあげる。
  3. rails app:updateの実行。
  4. rails app:updateによって発生したコンフリクトを解消。
  5. config.load_defaults5.2 -> 7.0に更新。
  6. RSpecの結果を確認しながら、バージョン起因で動かなくなっているgemを適宜アップデート。(bundle update {gem名}
    ※ 最初はbundle updateですべての依存gemを一度にアップデートしてみたのですが、バージョンが大きく変わるgemが存在しており、修正内容が大きくなりそうでした。
    そのため、最低限のみのアップデートに切り替えました。
  7. RSpecが落ちている箇所を確認し、コードを修正して動くようにする。
  8. config/initializers/new_framework_defaults_7_1.rbの設定を1つずつ有効にしていく。
    (設定値の変更が必要なものは、config/application.rbで該当の設定を記述する。)
  9. config/initializers/new_framework_defaults_7_1.rbを削除し、config.load_defaults7.1に更新する。

Rubyバージョンアップ

  1. DockerfileおよびGemfileのバージョンを更新する。
  2. CircleCIでのbuldle installコマンドに、環境変数GRPC_RUBY_BUILD_PROCSの追加。(詳細は大変だったこと&ハマったことを参照)

new_framework_defaults_7_1.rb

Rails 7.1で変更されるデフォルト設定値について、今回いくつか設定変更したものがあったため記載しておきます。

  • config.active_record.marshalling_format_version

    この方法でシリアライズされたモデルは古いバージョンのRails(< 7.1)では読み込めなくなります。

    上記記述の通り、新しい設定値にすると、万が一7.0に戻したくなった場合に苦労すると思われます。
    そのため、初期段階としては6.1(7.0以前と同じ動作)とし、7.1状態でしばらく運用後、7.0へ戻すことが100%ない状態となってから更新することとしました。

  • config.active_support.use_message_serializer_for_metadata

    この方法でシリアライズされたモデルは古いバージョンのRails(< 7.1)では読み込めなくなります。

    上記記述の通りであり、こちらの設定値も前項目と同様に、7.0へ戻すことが100%ない状態となってから更新することとしました。

  • config.active_support.message_serializer

    7.1のデフォルト値(:json_allow_marshal)状態でActiveSupport::MessageEncryptorを使って暗号化したものは、7.0では正常に複合化できませんでした。
    新しい値(:json_allow_marshal)にすると、7.1である限りは問題ないのですが、万が一7.0へ戻す必要が出てきた場合に苦労すると思われます。
    そのため、初期段階としては:marshal(7.0以前と同じ動作)とし、7.1状態でしばらく運用後、7.0へ戻すことが100%ない状態となってから更新することとしました。

大変だったこと&ハマったこと

config.load_defaultsの値が5.2だった

バージョンアップ前、Railsは7.0だったのですが、config.load_defaults5.2でした。
さすがに今回のタイミングで最新に更新したく、変更内容を確認していったのですが、それなりのボリュームがあり割と大変でした。
Railsバージョンアップの際は、config.load_defaultsまでしっかり対応するようにして、放置しないようにすることをオススメいたします!

※ もし、過去分のconfig/initializers/new_framework_defaults_x_y.rbを消してしまっていて存在しない場合は、こちらに各バージョンごとのデフォルト設定値一覧が載っているので、参考になるかと思います!(BALES CLOUDでは消してしまっていた模様で存在しなかったので、こちらを参考に確認しました!)

ローカルのsecret_key_baseの保存場所が変わっていた

BALES CLOUDではActiveSupport::MessageEncryptorを使って暗号化している処理があるのですが、7.0で暗号化したものが7.1で複合化できない事象が発生しました。
いろいろ調べて見ると、7.1からローカルでのsecret_key_base保存場所が変わっているようでした。
そのため、新しいファイル(tmp/local_secret.txt)の値を古いファイル(tmp/development_secret.txt)の値で上書きすることで、解消できました。

[参考]
Rails 7.1: ローカル環境のsecret_key_baseの保存場所がcredentialsに変わる(翻訳)|TechRacho by BPS株式会社

CircleCIでの"bundle install"ができなくなった

Rubyのバージョンアップを行なうと、CircleCIでReceived “killed” signalのエラーが発生し、bundle installが最後まで到達しない問題が発生しました。 以下を参考に、 GRPC_RUBY_BUILD_PROCSの環境変数を追加することで解消できました。
例)

command: |
  bundle install --jobs=4 --retry=3 --path vendor/bundle
environment:
  GRPC_RUBY_BUILD_PROCS: 4

[参考]
Florian Josef Reheis - CircleCI - Received killed signal

良かったこと&助かったこと

テストコード

今回コード修正が必要となった箇所のほとんどを、テストコードで検知しました。 テストコードで検知できたおかげで、開発プロセスのより早い段階で対応を行なうことができて、総工数の削減ができました!
テストコードを書いてくれていた現在および以前の開発メンバーに感謝です!

新しいデフォルト設定値

実は一度本番リリースの際に想定外の挙動が見つかり、リリースを中止したことがありました。
要因としては新しいデフォルト設定値が関係していたのですが、事前のデフォルト設定値確認で怪しいと思いながら新設定値を採用した箇所であったため、すぐに原因について見当がつき迅速に対応ができました。
今回config.load_defaultsが最新になっていなかったため(詳細はこちら) 、確認に時間を要しましたが、疎かにせずに確認してよかったかと思います!

最後に

長くなりましたが、これからRails 7.1またはRuby 3.3へアップデートする方へ、少しでもお役に立てれば幸いです!