クラウド経費 の開発を担当している野田 (@quanon_jp) と申します。
これまでにチームメンバーと僕とで以下のRuby on Rails(以下Rails)バージョンアップに関する記事を執筆しました。
moneyforward-dev.jp moneyforward-dev.jp
今回はその続編です。Railsのバージョンを7.1から7.2に更新しました。今回も更新の記録を残しておこうと思います。
EOL について
クラウド経費・クラウド債務支払のWebアプリケーションはRailsで構築されています。2025年7月1日時点ではRails 7.1を使用していますが、3ヶ月後にはEOLを迎えてしまいます。7.2に更新することでEOLまで1年以上の猶予が得られます。
Ruby on Rails — Maintenance policy より
| バージョン | バグ修正 | セキュリティ修正 (EOL) |
|---|---|---|
| 7.1.x | 2024/10/01 | 2025/10/01 |
| 7.2.x | 2025/08/09 | 2026/08/09 |
進め方
進め方は前回Rails 7.0から7.1に更新した際と同様なので省略します。
実際に対応したこと
実は前回の更新とは異なり、今回はほぼ何もせずに更新できました。具体的にはRailsの内部実装に依存した一部の実装を修正しただけです。具体的には ActiveRecord::InsertAll#initialize の引数がRails 7.1から7.2で変わっており、それをオーバライドしたクラスがあるので修正しました。
- https://github.com/rails/rails/blob/v7.1.5.1/activerecord/lib/active_record/insert_all.rb#L10
- https://github.com/rails/rails/blob/v7.2.2.1/activerecord/lib/active_record/insert_all.rb#L18
これだけだとブログの内容が具なしラーメンのように寂しいので、Railsのバージョン更新前にやったとある対応についてお話しします。
config.load_defaults について
Railsのバージョン更新は以下の流れで行いました。
- Rails 7.0を7.1に更新する
config.load_defaultsを7.0から7.1に更新する- Rails 7.1を7.2に更新する
config.load_defaultsを7.1から7.2に更新する(対応中)
この config.load_defaults の7.0から7.1への更新が大変でした。
config.load_defaults とは、指定したRailsバージョンのデフォルト設定を一括で読み込むための設定で、config/application.rb でバージョンを指定します。Railsのバージョンを更新すると、既存の設定のデフォルト値変更も行われます。Railsは巨大なフレームワークであり設定の項目数も多いので、バージョンアップのたびに設定値の変更に追従するのは大変です。そこで、実際のRailsのバージョンは7.1ですが、 config.load_defaults のバージョンには7.0を指定しておくことで、とりあえず前のバージョンの設定値を引き継ぐことができます。
とはいえ、Railsのバージョン更新時に非推奨の設定が削除されたり、設定値が廃止されたりするなど破壊的変更を伴うことがあります。そのため、config.load_defaults のバージョンをRailsのバージョンにできるだけ速やかに合わせることが望ましいです。config.load_defaults を更新する流れについては以下の記事に詳しく記載されており、僕もそれに則って更新しました。
config.load_defaults を7.0から7.1に更新する場合は config/initializers/new_framework_defaults_7_1.rb に記載されている設定項目を確認します。
具体的には以下の30項目です。クラウド経費・クラウド債務支払のRailsアプリケーションが規模が大きいため、アプリケーションの挙動に影響を与えることがないようにひとつひとつの項目を丁寧に確認しました。
- config.add_autoload_paths_to_load_path
- config.action_dispatch.default_headers
- config.action_controller.allow_deprecated_parameters_hash_equality
- config.active_support.key_generator_hash_digest_class
- config.active_record.encryption.hash_digest_class
- config.active_record.encryption.support_sha1_for_non_deterministic_encryption
- config.active_record.run_commit_callbacks_on_first_saved_instances_in_transaction
- config.active_record.sqlite3_adapter_strict_strings_by_default
- config.active_record.allow_deprecated_singular_associations_name
- config.active_job.use_big_decimal_serializer
- config.active_support.raise_on_invalid_cache_expiration_time
- config.active_record.query_log_tags_format
- config.active_support.message_serializer
- config.active_support.use_message_serializer_for_metadata
- config.log_file_size
- config.active_record.raise_on_assign_to_attr_readonly
- config.active_record.belongs_to_required_validates_foreign_key
- config.filter_parameters
- config.precompile_filter_parameters
- config.active_record.before_committed_on_all_records
- config.active_record.default_column_serializer
- config.active_record.marshalling_format_version
- config.active_record.run_after_transaction_callbacks_in_order_defined
- config.active_record.commit_transaction_on_non_local_return
- config.active_record.generate_secure_token_on
- config.active_support.cache_format_version
- config.action_view.sanitizer_vendor
- config.action_text.sanitizer_vendor
- config.action_dispatch.debug_exception_log_level
- config.dom_testing_default_html_version
可能な限りRails 7.1での新しいデフォルト値に切り替えていきましたが、既存の振る舞いへの影響範囲が想定しにくい設定値に関しては、いったん7.0のデフォルト値を保持しました。例えばコールバックが呼ばれる順番を設定する config.active_record.run_after_transaction_callbacks_in_order_defined は、after_commitを複数宣言しているモデルが少なかったので、コールバックの順番を入れ替えつつ、新しいデフォルト値に変更しました。一方でトランザクションのコミットに関する config.active_record.run_commit_callbacks_on_first_saved_instances_in_transaction に関しては、既存の振る舞いに影響しないことを保証できなかったのでこれまでのデフォルト値を保持しました。
config.load_defaults を更新するためには多くの設定値について調べる必要があるので大変ですが、Railsについて詳しくなれるというメリットがあります。例えば config.active_record.commit_transaction_on_non_local_return について調べることで「transactionブロック内でreturnする場合は、これまではトランザクションをロールバックしていましたが、今後はトランザクションはコミットされる」ということがわかります。また、この設定についてRailsガイド、あるいは対応された際のPRを確認すると
Historically only raised errors would trigger a rollback, but in Ruby 2.3, the timeout library started using throw to interrupt execution which had the adverse effect of committing open transactions. To solve this, in Active Record 6.1 the behavior was changed to instead rollback the transaction as it was safer than to potentially commit an incomplete transaction. Using return, break or throw inside a transaction block was essentially deprecated from Rails 6.1 onwards. However with the release of timeout 0.4.0, Timeout.timeout now raises an error again, and Active Record is able to return to its original, less surprising, behavior.
と記載されており、設定値が変更された経緯や本来transactionブロック内でのreturn, break, throwの使用が非推奨なことを知ることができます。
なお、Railsを7.1から7.2に更新した後も同様に、config.load_defaults を7.1から7.2に更新中です。こちらは設定項目がたったの5項目なのですぐに終わりそうです。
まとめ
Railsを7.1から7.2に更新すること自体は容易でしたが、その前準備として config.load_defaults を7.1に更新するのが大変でした。しかし、Railsのバージョンアップを丁寧に行うことで、アプリケーションの品質向上に寄与できるだけでなく、Railsの知識を身につけることもできます。ぜひチャレンジしてみてください。
マネーフォワード福岡開発拠点ではエンジニアを募集しています!多くのユーザーに利用されているRailsアプリケーションに携わりたい方はぜひ!
福岡開発拠点のサイトもあります。もしご関心があれば、ぜひともご覧ください!