`require_dependency` の非推奨化と Rails 9 での削除に向けた準備
require_dependency がdeprecated(非推奨)となり、Rails 9 での削除に向けたプロセスが開始されました。classic オートローダーとの互換性維持のために残されていたこのメソッドに、呼び出し時の警告と移行ガイダンスが追加されています。
背景
require_dependency は、Rails の classic オートローダーから Zeitwerk ベースのオートローダーへの移行を支援するために維持されてきたメソッドです。classic オートローダーでは、定数解決が Ruby のデフォルト動作と異なっていたため、ロード順序を明示的に制御する目的で require_dependency が使われていました。Rails 7.0 で classic オートローダーのサポートが終了した現在、このメソッドが存在する主な理由は Rails < 7.0 をサポートするエンジンへの配慮でした。
Zeitwerk ベースのオートローダーでは定数解決のセマンティクスが Ruby 標準に準拠しており、require_dependency による明示的なロード制御は不要です。PR 本文でも「classic からの移行を容易にするために残してきたが、そろそろ削除の準備を始めてよい時期だ」と述べられており、今回の非推奨化はその第一歩に当たります。
技術的な変更
require_dependency の実装に ActiveSupport.deprecator.warn による警告が追加され、呼び出し時に非推奨メッセージが出力されるようになりました。
変更前:
module ActiveSupport::Dependencies::RequireDependency
# <b>Warning:</b> This method is obsolete. The semantics of the autoloader
# match Ruby's and you do not need to be defensive with load order anymore.
# Just refer to classes and modules normally.
#
# Engines that do not control the mode in which their parent application runs
# should call +require_dependency+ where needed in case the runtime mode is
# +:classic+.
def require_dependency(filename)
filename = filename.to_path if filename.respond_to?(:to_path)
# ...
end
end
変更後:
module ActiveSupport::Dependencies::RequireDependency
# <b>Warning:</b> This method is deprecated.
def require_dependency(filename)
ActiveSupport.deprecator.warn <<~MSG
require_dependency is deprecated without replacement and will be removed
in Rails 9.
- Recommendations for applications:
- If the call is an old one written in the days of the classic autoloader to ensure a
certain constant is loaded for constant lookup to work as expected, you can simply
remove it.
- In order to preload classes when the application boots, which may be necessary for
things like STIs or Kafka consumers, please check the autoloading guide for modern
approaches.
- Recommendations for engines that depend on Rails >= 7.0:
Same recommendations as for applications, since the classic autoloader is no longer
available starting with Rails 7.0.
- Recommendations for engines that support Rails < 7.0:
Guard the call with a version check just in case the parent application is using
the classic autoloader:
require_dependency "some_file" unless Rails::VERSION::MAJOR >= 7
MSG
filename = filename.to_path if filename.respond_to?(:to_path)
# ...
end
end
警告メッセージは状況に応じた3種類の移行ガイダンスを含んでいます:
- アプリケーション向け: classic オートローダー時代の呼び出しであれば単純に削除可能。STI や Kafka コンシューマーなどブート時の事前ロードが必要な場合はオートローディングガイドの現代的アプローチを参照。
- Rails >= 7.0 をサポートするエンジン向け: アプリケーションと同じ対応が可能。
- Rails < 7.0 をサポートするエンジン向け: バージョンチェックで親アプリが classic オートローダーを使う場合に限り呼び出すよう条件分岐を追加。
テストファイルでは、既存テストの require_dependency 呼び出しが silenced_require_dependency ヘルパーでラップされ、テスト実行中に非推奨警告が出力されないよう対応されています。また、mutual_one.rb・mutual_two.rb・requires_nonexistent1.rb の3つのテスト用フィクスチャファイルは、require_dependency を呼び出すだけの内容だったため削除されています。
設計判断
警告メッセージに移行ガイダンスを直接埋め込む設計が採用されました。単に「非推奨」と通知するだけでなく、利用者の状況(アプリケーション、Rails >= 7.0 対応エンジン、Rails < 7.0 対応エンジン)ごとの対処法を警告文中に記載することで、ドキュメントを別途参照せずとも次のアクションが取れるようになっています。
ActiveSupport.deprecator.warn を使うことで、Rails の標準的な非推奨警告の仕組みに乗っています。これにより、テスト環境では ActiveSupport.deprecator.silence ブロックで警告を抑制できるため、既存テストの継続実行が容易になっています。代替手段なしの削除という判断も注目に値します。Zeitwerk への移行が完了しているという前提に立ち、wrapper API を新設せず、そのまま削除する方向が選ばれています。
まとめ
本PRは、Rails の classic オートローダー時代の遺産である require_dependency を段階的に取り除くための非推奨化ステップです。警告メッセージに具体的な移行ガイドを埋め込むことで、各種エンジンやアプリケーションの対応を促しながら、Rails 9 でのクリーンな削除に向けた地ならしを行っています。