Rails で開発をしている際、 layout ファイル中の要素を特定のページでのみ変更したくなることがしばしばある。
例えば、次のような app/views/layouts/application.html.haml
があり、ページによってサイドメニューの内容を変えたいというユースケースを考える。
%html
%head
-# ...
%body
.side-menu
-# この部分をページによって変更したい
= render 'side_menu'
%main
= yields
ダサい例: pathによる分岐
次のようにページの URL によって分離する方法をよく見かける。
- if request.path == '/'
= render 'root_side_menu'
- else
= render 'side_menu'
このようなやり方でしか解決できない場合もあることは認めるが、しかしクソダサい方法だと思う。
共通部分であるレイアウト側が特定部分である URL や View のことを気にしなければならない感じが嫌だし、対応しなければならない URL が増えるたびに条件式を変更しなければならないのも嫌だ。View の Template ファイル中ではこの分岐に全く触れることが出来ないのも、ロジックが分散している感じがして嫌だ。
格好いい例: content_for を使う
もっと宣言的に書こう。 yield
と content_for
を使うほうがずっといい。
まず、 layout ファイルを次のように変更しよう。
%html
%head
-# ...
%body
.side-menu
= yield :side_menu
%main
= yield
次に、View の Template に content_for
で表示したい内容を渡す。
-# root の view の Template
= content_for :side_menu do
= render 'root_side_menu'
-# 他の部分の Template
= content_for :side_menu do
= render 'side_menu'
Rails の View の yield
に Symbol を渡すと、その Symbol 名を引数に持つ content_for
を探して、content_for
のブロックを yield
の部分に差し込む。
content_for
の宣言がViewファイル間で重複するのが気になる場合はHelper メソッドに逃がすなどすればいい。