Railsを「6.1.4.1 → 7.1.3.4」にアップデートするまでに行ったこと
IT技術
はじめに
今回は、私が担当しているプロジェクトで、Railsを「6.1.4.1 → 7.1.3.4」までバージョンアップを行なったため、どのような流れで行ったかご紹介させていただけたらと思います。
【バージョンアップ前の環境】
- docker環境
- image: ruby:3.0.6-alpine
- rails 6.1.4.1
- ruby 3.0.6
【参考資料】
以下の記事が大変参考になりました。
https://qiita.com/jnchito/items/0ee47108972a0e302caf
記事をベースに以下の流れで行っていきました。
- 使用していない不要なコード
- 使用していないgemの削除
- rails以外のgem、rubyのバージョンアップ
- railsを7.0.8.4にバージョンアップ
- railsを7.1.3.4にバージョンアップ
1. 使用していない不要なコード
まずは、不要なコードを削除を行いました。
上記の作業を行う理由としては、以下になります。
- バージョンアップによる影響が不要なコードに及んでエラーになるのを避けたい
- コードの見通しがよくなり、その後の対応がしやすくなる。
- プロジェクト内を全文検索をする時に、使用していないコードがヒットすると該当のコードを探しにくになるなど
バージョンアップ前に、コードを全体的にすっきりさせておくとなにかと対応がしやすくなるのは、なんとなくイメージがつくかと思います。
2. 使用していないgemの削除
この後の作業でgemのアップデートを行う前に、まずは使用していないgemを削除します。
使用していないgemをアップデートするのは無駄な作業なので、こちらの作業を行いました。
gemのREADMEから使用方法を確認して、VScodeの全文検索で使用しているか確認していきます。
前作業で、使用していないコードを削除したおかげで、全文検索でヒットしたコードは使用しているコードなのでコードを綺麗にしておいてよかったなと思いました。
3. rails以外のgem、rubyのバージョンアップ
ここからバージョンアップ作業に入ります。
記事では、まとめてgemのバージョンアップをする工程がありますが、自分は複数のgemのバージョンをあげてエラーが重なり解決に時間がかかるのを避けるため、開発環境テスト環境で使用するgemだけまとめてアップデートし、それ以外は以下の流れで1つずつバージョンアップしていきました。
◾️gemのバージョンをあげ、問題なくgemの機能を利用できていることを確認(テストで担保できる場合はテスト実行)
この時、rubyのバージョンが上げなくてもgemをバージョンアップできる所まで、上げていきました。
途中rubyのバージョンを上げないとバージョンアップできなくなった時にrubyのバージョンを上げました。
4. rails 7.0.8.4にバージョンアップ
一気に最新まで上げるのは怖いので、一旦7.0系の最新までバージョンアップしました。
事前にアップグレードガイドとリリースノートを確認して、アプリケーションと関係がありそうな箇所を把握しておきます。
アップデート内容の中でも特に以下の変更点は、特に重要です。
暗号化アルゴリズムやオートロードのモード変更やキャッシュのシリアライズフォーマットの変更はアプリケーションに重大な影響を及ぼすので慎重に対応が必要です。
- アプリケーションはzeitwerkモードでの実行が必須
- キージェネレータのメッセージダイジェストクラスでcookieローテーターが必須になった
- ActiveSupport::Digestで用いられるメッセージダイジェストクラスがSHA256に変更
- ActiveSupport::Cacheの新しいシリアライズフォーマット
railsのバージョンを上げた後は、「rails app:update」を実行して、新バージョンで必要な設定を反映していきます。
反映内容は、全て「上書き更新」しました。
理由としては、バージョンアップによる更新内容を全てコミットしてまとめておきたいためです。
上記コミットを作成した後で、反映して良い設定項目は反映し、戻したい内容は戻していきます。
これにより、レビューする時に「バージョンアップによる更新内容を確認した上で、最終的な変更内容」を確認でき、レビューがしやすくなります。
アップデート後は、STG環境で動作検証し問題なければ完了です。
7.0.8.4にバージョンアップ時に起こった問題を一部紹介
テスト実行時にエラー
NoMethodError: undefined method `enabled?'
rspecのテスト実行時に上記のエラーが発生しました。
原因はセッションをモック方法が変更になったためです。
こちらの記事を参考に以下のようにモック方法で解消しました。
1# spec/rails_helper.rb
2config.before(:each) do
3 # let(:rspec_session) で指定された値を セッションの初期値にする
4 session = defined?(rspec_session) ? ActionController::TestSession.new(rspec_session): ActionController::TestSession.new({})
5
6 # sessionメソッドを上書き
7 allow_any_instance_of(ActionDispatch::Request).to receive(
8 :session
9 ).and_return(session)
10end
異なるrailsバージョン間でセッションを共有できない
こちらはかなりレアケースですが、開発していたサービスが以下のような構成になってる時に起こった問題です。
rails3、rails7が同時稼働しており、セッションをmemcachedに保存し共有し合っている。 |
ただセッションの扱い方が異なっていることでrails7側でセッションを参照することができませんでした。(rails6の時はHashクラスでも参照できるようになっていました)
- rails3
- セッションをHashクラスで扱っている
- rails7
- セッションをEntryクラスで扱っている
1つ目の対応
rails7からキャッシュ保存時のシリアライズフォーマットが変更されてました。
これによりセッションを保存する時も影響があります。
rails3が稼働している以上、この設定を適用するわけにはいかないので以下のように6.1の頃の設定を使用するようにしました。
1config.active_support.cache_format_version = 6.1
2つ目の対応
rails7で参照するためには、Entryクラスで扱うようにする必要がありました。(Entryクラスはrails内で定義しているクラス)
そのため以下のようにモンキーパッチを当て、HashクラスをEntryクラスで扱うように変更し解決しました。
1module ActiveSupport
2 module Cache
3 class MemCacheStore < Store
4 def deserialize_entry(payload, raw: false, **)
5 # こちらコード追加。Hashクラスの場合、rawを「true」にして、Entryクラスを生成する
6 raw = true if payload.is_a?(Hash)
7
8 if payload && raw
9 Entry.new(payload)
10 else
11 super(payload)
12 end
13 end
14 end
15 end
16end
異なるrailsバージョン間で保存したセッションを参照するとエラー
これまたrails3、rails7が同時稼働していることで起こった問題です。
特定の動作をし、ページ遷移すると以下のエラーが発生しました。
dump format error (user class)
ログを見るとセッション情報を取得する時にMarshalモジュールでデシリアライズする時に発生しているエラーのようでした。
(エラーはmemcachedクライアントgemのdalli gem内の処理で発生)
以下の調査からrails3内で「Hash, Array, String, Regexpクラス」のサブクラスのインスタンスをセッションに保存した時に、rails7では対象のクラスのインスタンスをデシリアライズできずにエラー発生することを特定しました。
- 「dump format error (user class)」のエラーはここで返されている
- 上記の処理は、「case TYPE_UCLASS」内で発生している
- 「TYPE_UCLASS」には「C」が設定されている
- 「Marshalフォーマット」には「String, Regexp, Array, Hash のサブクラスはCで始まるデータ構造」になると記載がある
実際の原因としては、rails3で「HashクラスのサブクラスのActionController::Parametersクラスのインスタンス」がセッションに保存されていました。
「ActionController::Parametersクラス」はrails5以降かなり改変されているのでrails7ではデシリアライズできなかった形です。
この問題はrails6でも起こり得る問題だったのですが、rails6ではエラーは発生せず、セッションは見つからずに新規セッションが作成される挙動になっていたので、発見できておりませんでした。
解決策としてrails3で「ActionController::Parametersクラス」ではなくプレーンな「Hashクラス」で保存することでエラーを回避し、セッションを正常に共有することができました。
5. rails 7.1.3.4にバージョンアップ
流れは7.0.8.4にバージョンアップした時と同じです。
事前にアップグレードガイドとリリースノートを確認しておきます。
7.1の特に重要な変更点は以下になります。
マイナーバージョンのアップデートのため、7.0.8.4に上げた時より比較的確認項目は少なかったです。
7.1へのバージョンアップは7.0に上げた時ほど大きな問題はありませんでした。
アップグレードガイドとリリースノートを確認して対応していけば大丈夫かと思います。
アップデート後は、STG環境で動作検証し問題なければ完了です。
最後に
自身のプロジェクトでは異なるrailsのバージョンが同時稼働している状況だったため、エラー回避に苦労しましたが、そうでない場合は「アップグレードガイド」「リリースノート」「バージョンアップについての記事」が充実しているので、焦らず丁寧に対応していけば安全にバージョンアップできるのではないでしょうか。
この記事がどなたかの参考になれば幸いです。
ライトコードでは、エンジニアを積極採用中!
ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。
採用情報へ
服部晋平と申します! 前職では映像業や配送業に携わっていました。 趣味は、バイクツーリングに行ったり、美味しいラーメン屋巡りです。 未経験という身で入社させていただいたので、人一倍努力して頑張っていきたいと思います!