ViewExampleGroupでコントローラパスをlookup_context prefixesの先頭に配置
RSpec Railsのビュースペックにおいて、lookup_context.prefixesへのコントローラパス追加方法が変更されました。末尾への追加(<<)から先頭への挿入(prepend)に変更することで、Railsのビューレンダリングが前提とする「最初のprefixがコントローラのパス」という規約に準拠します。
背景
Railsのビューレンダリングは、lookup_context.prefixesの最初の要素がコントローラのパスであることを前提としています。ActionView::AbstractRenderer::ObjectRendering#initializeでは、@context_prefix = lookup_context.prefixes.firstとして最初のprefixを取得し、パーシャルのレンダリングパスを構築します。
しかし、rspec-railsのViewExampleGroupは従来、コントローラパスをprefixesの末尾に追加していました。#2729で報告されたとおり、この実装ではprefixes.firstが空文字列を返し、ネストされたコントローラ内でパーシャルの解決に失敗するケースがありました。
merge_prefix_into_object_pathメソッドの挙動を修正するモンキーパッチを適用した際に、この問題が顕在化しています。Railsの期待する順序に従わないprefixの構築は、本来機能すべきビューの解決を妨げる原因となります。
技術的な変更
lib/rspec/rails/example/view_example_group.rbのbeforeフック内で、コントローラパスをprefixリストに追加する処理が変更されました。
変更前:
before do
_include_controller_helpers
view.lookup_context.prefixes << _controller_path
controller.controller_path = _controller_path
end
変更後:
before do
_include_controller_helpers
view.lookup_context.prefixes.prepend(_controller_path)
controller.controller_path = _controller_path
end
<<演算子による末尾への追加から、prependメソッドによる先頭への挿入に変更されました。これにより、lookup_context.prefixes.firstが確実にコントローラパスを返すようになります。
回帰テストとして、新たなspecが追加されています:
it 'injects controller path as first prefix' do
prefixes = []
RSpec.describe "a view spec" do
include ::RSpec::Rails::ViewExampleGroup
def _controller_path
"example/path"
end
specify do
prefixes = view.lookup_context.prefixes
end
end.run
expect(prefixes).to start_with("example/path")
end
このテストは、_controller_pathがprefixesの先頭要素として存在することを検証します。コメントにはActionView::AbstractRenderer::ObjectRendering#initializeへの参照とともに、#2729の回帰防止である旨が明記されています。
設計判断
Railsフレームワークの規約を優先する方針が採られました。
Railsのビューレンダリングシステムは、prefixリストの順序に依存した実装になっています。@context_prefix = lookup_context.prefixes.firstという実装は、Railsが「最初のprefixは常にコントローラのパス」と想定していることを示します。
rspec-rails側で独自の順序を採用するのではなく、Railsの期待する順序に合わせる実装を選択することで、フレームワークとの整合性を保っています。この判断により、将来的にRails側のビューレンダリングロジックが変更された場合でも、rspec-railsのテストが予期しない挙動を示すリスクが軽減されます。
まとめ
本PRは、ViewExampleGroupのprefixリスト構築をRailsの規約に準拠させる1行の変更です。prependへの変更により、lookup_context.prefixes.firstがコントローラパスを返すことが保証され、ネストされたコントローラでのパーシャル解決が正しく機能するようになります。フレームワークの期待に沿った実装に修正することで、テストの信頼性が向上しています。