先日、仕事中に少し嵌ったpartialの振る舞いについてまとめます。
環境
Rails 5.1.4
内容
例えば、以下のようなディレクトリ構成のViewがあるとします。
もちろん、Controllerとcofig/routes.rb
は適切に設定されています。
view/
├── layouts/
└── test/
├── index.html.haml
├── _child.html.haml
└── _grandson.html.haml
= render partial: 'child'
= render partial: 'grandson'
%p hoge from test
/testにアクセスすれば、当然、hoge from test
と表示されます。この振る舞いについては自然に思われます。
次にTest2Controller.rb
を作成し、以下のようにindex.html.haml
を追加します。
view/
├── layouts/
├── test/
│ ├── index.html.haml
│ ├── _child.html.haml
│ └── _grandson.html.haml
└── test2/
└── index.html.haml
= render partial: 'test/child'
この様な場合も、hoge from test
と表示されるものと私は期待したのですが、実際には以下のようなエラーになりました。
Missing partial test2/_grandson, application/_grandson with {:locale=>[:en], :formats=>[:html], :variants=>[], :handlers=>[:raw, :erb, :html, :builder, :ruby, :ts, :haml, :jbuilder]}. Searched in:
* "/#{アプリケーションのディレクトリ}/app/views"
これをみるとtest/_grandson
ではなく、test2/_grandson
を見にいってしまっていることがわかります。
そこで、以下のファイルを追加すると、
%p hoge from test2
hoge from test2
と表示されます。
つまり、相対パスの基準はpartialのディレクトリではなく、呼出元のhamlがあるディレクトリに依存するというわけです。
test2でも test/_grandson
をみるようにするためには、view/
からの相対パスで書けばよいです。
= render partial: 'test/grandson'
結論
view/
からの相対パスで書くのが安全かもしれません。
(view/
からの相対パスで書かないのはバッドプラクティスといえるほど経験を積んでいないので、可能性の示唆に留めて置きます。そういう言明があれば教えていただきたいです。)