⚠️

Rails 7.0 から 7.1 へのアップグレード時のトラブルと対応策

に公開

参考:Rails アップグレードガイド – Railsガイド

Railsバージョンアップ

Gemfile
- gem 'rails', '~> 7.0.8.7'
+ gem 'rails', '~> 7.1.5.1'
$ bundle update

Rails 7.1 への移行で発生した問題とその解決策

プロジェクトで Rails 7.0.8.7 から 7.1.5.1 へのバージョンアップを実施した際に、いくつかの問題が発生しました。主に、既存の設定や依存関係との互換性の問題が見られました。以下に、発生した問題とそれに対する解決策をまとめます。

1. composite_primary_keys gemの非対応

発生した問題

composite_primary_keys gemがRails 7.1 に未対応で使えなくなりました。

参考:Is gem still relevant with Rails 7.1?

~/g/g/U/herokura (*´ω`*) < bundle update rails                                                                                                                                                                                                                                       19:59:11
Fetching gem metadata from https://rubygems.org/.........
Resolving dependencies...
Could not find compatible versions

Because composite_primary_keys >= 14.0.1, < 14.0.4 depends on activerecord ~> 7.0.0
  and composite_primary_keys >= 14.0, < 14.0.1 could not be found in rubygems repository https://rubygems.org/ or installed locally,
  composite_primary_keys >= 14.0, < 14.0.4 requires activerecord ~> 7.0.0.
And because composite_primary_keys >= 14.0.4 depends on activerecord ~> 7.0.2
  and rails >= 7.1.5.1, < 7.2.0.beta1 depends on activerecord = 7.1.5.1,
  composite_primary_keys >= 14.0 is incompatible with rails >= 7.1.5.1, < 7.2.0.beta1.
So, because Gemfile depends on rails ~> 7.1.5.1
  and Gemfile depends on composite_primary_keys ~> 14.0,
  version solving has failed.

しかしRails 7.1では、ネイティブで複合主キーがサポートされるようになったため、composite_primary_keys gemは不要になりました。

解決策

  • composite_primary_keys gemを削除。
  • self.primary_keysself.primary_keyに変更。
- self.primary_keys = :first_name, :last_name
+ self.primary_key = [:first_name, :last_name]

2. foreign_key配列の非推奨

発生した問題

/Users/matsumoto_t/ghq/github.com/UUUM/herokura/vendor/bundle/ruby/3.2.0/gems/activerecord-
7.1.5.1/lib/active_record/reflection.rb:446:in `validate_reflection!': Passing [:process_id, :employee_account_code]
 array to :foreign_key option on the Organization::ImportEmployee#import_depart
ment_employees association is not supported. Use the query_constraints: [:process_id, :employee_account_code]
 option instead to represent a composite foreign key. (ArgumentError)                                                                                                            
                                                                                                                                                                                                                                                                                              
          raise ArgumentError, message
                ^^^^^^^^^^^^^^^^^^^^^^

解決策

has_manybelongs_toで複合外部キーを使用する場合、foreign_keyではなくquery_constraintsを使用するように変更。

- has_many :employees, foreign_key: [:process_id, :employee_account_code]
+ has_many :employees, query_constraints: [:process_id, :employee_account_code]

参考:複合主キーを持つモデルの関連付け

3. secret_key_baseの保存場所変更

Rails 7.1では、ローカル環境のsecret_key_baseの保存場所がcredentialsに移行しました。

発生した問題

下記エラーはDevise が Rails.application.secrets.secret_key_base を参照している ため発生しました。

/Users/matsumoto_t/ghq/github.com/UUUM/herokura/vendor/bundle/ruby/3.2.0/gems/devise-
4.9.4/lib/devise/secret_key_finder.rb:12:in `find': DEPRECATION WARNING: `Rails.application.secrets` is deprecated in favor of
 `Rails.application.credentials` and will be removed in Rails 7.2. (called 
from <main> at /Users/matsumoto_t/ghq/github.com/UUUM/herokura/config/environment.rb:5) 
(ActiveSupport::DeprecationException)

解決策

Rails.application.secrets.secret_key_baseRails.application.secret_key_baseに変更。

config/initializrs/devise.rb
Devise.setup do |config|
+ config.secret_key = Rails.application.secret_key_base
end

4. Enumの属性定義

発生した問題

Rails 7.1では、 Enum を使用する場合、属性がデータベースに存在しない場合には、明示的に attribute を定義する必要があります。

Undeclared attribute type for enum 'stagename_options' in Sample. Enums must be backed 
by a database column or declared
 with an explicit type via `attribute`. (RuntimeError) 

解決策

以下のようにattributeを追加してからenumを定義。

+ attribute :stagename_options, :string
enum :stagename_options, { 'TestStage1' => 'TestStage1', 'TestStage2' => 'TestStage2', 'TestStage3' => 'TestStage3' }

5. Zeitwerkとrequireの競合

発生した問題

テスト時にrequireとZeitwerkのオートローディングが競合してエラーが発生しました。

<internal:/Users/matsumoto_t/.rbenv/versions/3.2.6/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:38
:in `require': cannot load such file -- example_module/order_type (LoadError)

Zeitwerk は autoload_paths に含まれるディレクトリのファイルを自動で読み込む仕組みを持っています。
そのため、通常は require を使わなくても、ファイルが適切な場所にあれば自動的にロードされます。

解決策

Zeitwerkが自動でファイルをロードするため、明示的なrequireは削除。

test/workers/example_worker_test.rb
require 'test_helper'
- require 'example_module/order_type'

6. ActionController::Parametersのキー制限

発生した問題

Rails 7.1では、ActionController::ParametersのキーにStringSymbol以外を使用できなくなりました。

ActionController::InvalidParameterKey:                                                                                                                                                                                                                                                                                   
  all keys must be Strings or Symbols, got: Integer

解決策

ActionController::Parametersのキーに使用する値がStringまたはSymbolになるよう修正。
参考:Only allow String and Symbol keys in ActionController::Parameters

7. table_nameの代替

発生した問題

Rails 7.1 でArel::Tableからtable_nameメソッドが削除されました。

NoMethodError: undefined method `table_name' for #<Arel::Table:0x00000001525d6e18

解決策

table_nameメソッドをname属性に置換。
参考:Drop unused table_name alias from Arel::Table

8. ActiveSupport::Loggerのbroadcastメソッド削除(sidekiq内部のエラー)

発生した問題

Sidekiq内でbroadcastメソッドが削除され、エラーが発生しました。

~/g/g/U/herokura 。+゚(∩´﹏'∩)゚+。 < bundle exec sidekiq -C config/sidekiq.yml 
WARN: NoMethodError: undefined method `broadcast' for ActiveSupport::Logger:Class

解決策

Sidekiqを 6.5 から 7.2.2 にアップデートで解決。

参考:Logger.broadcast removed from ActiveSupport causing sidekiq to break

9. ActiveSupport::Loggerのbroadcastメソッド削除(アプリケーションのlogger設定箇所のエラー)

発生した問題

ActiveSupport::Loggerからbroadcastメソッドが削除されたためlogger設定箇所でエラーになりました。

WARN: NoMethodError: undefined method `broadcast' for ActiveSupport::Logger:Class

解決策

代わりにBroadcastLoggerクラスが追加されたためそれを適応。

lib/tasks/acl.rake
def logger
  @logger ||= Rails.logger.dup.tap do |logger|
-   logger.extend(
-     ActiveSupport::Logger.broadcast(
-       ActiveSupport::Logger.new($stdout)
-     )
+   # ブロードキャスト用のロガーを生成
+   broadcast_logger = ActiveSupport::BroadcastLogger.new(
+     ActiveSupport::Logger.new($stdout)
    )
+   # ロガーにブロードキャスト用のロガーを設定
+   logger.instance_variable_set(:@broadcast_logger, broadcast_logger)
  end
end

参考:Add a public API for broadcasting logs

10. clear_active_connections!の非推奨化

発生した問題

ActiveRecord::Base.clear_active_connections!が非推奨されました。

~/g/g/U/herokura 。+゚(∩´﹏'∩)゚+。 < bundle exec sidekiq -C config/sidekiq.yml 
WARN: ActiveSupport::DeprecationException: DEPRECATION WARNING: Calling `ActiveRecord::Base.clear_active_connections! is deprecated. Please call the method directly on the connection handler; for example: `ActiveRecord::Base.connection_handle
r.clear_active_connections!`. (called from block (2 levels) in <main> at /Users/matsumoto_t/ghq/github.com/UUUM/herokura/config/initializers/sidekiq.rb:6)
WARN: config/initializers/sidekiq.rb:6:in `block (2 levels) in <main>'
DEPRECATION WARNING: Calling `ActiveRecord::Base.clear_active_connections! is deprecated. Please call the method directly on the connection handler; for example: `ActiveRecord::Base.connection_handler.clear_active_connections!`. (called from block (2 levels) in <main> at /Users/matsumo
to_t/ghq/github.com/UUUM/herokura/config/initializers/sidekiq.rb:6)    

解決策

ActiveRecord::Base.connection_handler.clear_active_connections!に変更。

config/initializers/sidekiq.rb
- ActiveRecord::Base.clear_active_connections!
+ ActiveRecord::Base.connection_handler.clear_active_connections!

参考:Deprecate delegation to connection handler from Base

Discussion