`yield :foo`と`content_for :foo`の使い分け
56 views
Post
Conventions and helpers for building web pages on Rails.
Railsのactionviewのヘルパー関数には、form_with
のように、blockを活用して入れ子のHTML要素を記述できる便利なヘルパーメソッドがあります。
具体的には、以下のような記述(Railsガイドより引用)が出来るヘルパーメソッドです。
<%= form_with url: "/search", method: :get do |form| %>
<%= form.label :query, "Search for:" %>
<%= form.text_field :query %>
<%= form.submit "Search" %>
<% end %>
blockを用いてHTML要素の入れ子を出力できるこのようなヘルパーメソッドの自作に関する話です。
actionviewのcapture
というヘルパーメソッドを用いると、form_with
のように、blockを使ってHTML要素の入れ子を記述できるヘルパーメソッドを自作できます。
ちなみに、このcapture
は、Railsガイドを読んでも、RailsのAPIドキュメントを読んでも、いまいち使い道が分かっていなかったのですが、このような自作ヘルパーで使うというのが1つの使い道のようです。
def some_helper(content=nil, &block)
object_passed_to_block = 'hello, capture'
content = capture(object_passed_to_block, &block) if block
tag.div(content, class: 'some-class')
end
<%= some_helper do |object| %>
<p><%= object %></p>
<% end %>
<div class="some-class">
<p>hello, capture</p>
</div>
some_helper do |object|
tag.p(object)
end
<div class="some-class"><p>hello, capture</p></div>
some_helper('123')
<div class="some-class">123</div>
動機
Rails 8.0.2でrails newをして生成されたapp/views/layouts/application.html.erbでは、 以下のように
yield :foo
とcontent_for :foo
が混在していました。content_forのAPIドキュメントによれば
yield :foo
とcontent_for :foo
の働きが等価となる場合もあるのですが、 このapplication.html.erbの例のように、片方に統一されず両方を利用しているケースがあったので、yield :foo
とcontent_for :foo
の使い分けについて調べる事にしました。結論
yield :foo
を使う。ただし、以下の2つのケースではcontent_for :foo
を使う。content_for :foo
を使う。content_for :foo
を使う。詳細
yieldはヘルパーメソッドの中では利用できない
content_forのAPIドキュメントに書かれている通り、 content_forは以下の例のようにヘルパーメソッド内で利用可能ですが、yieldは利用できません。
yieldとcontent_forでは、設定されていないときの戻り値が異なる
ビュー側で以下のように:fooに対して設定が行われていた場合、
yield :foo
とcontent_for :foo
の戻り値は、この例ではどちらも" Foo\n"
であり、同じになります。しかし、ビュー側で前述のような記述がなく:fooに対して設定が行われていなかった場合、
yield :foo
の戻り値が空文字列(""
)であるのに対し、content_for :foo
の戻り値はnil
であり、 戻り値が異なります。設定されていない場合に
content_for :foo
がnil
を戻す性質を利用することで、<title><%= content_for(:title) || "Sample" %></title>
のような設定されているかどうかに応じて挙動を切り替えるコードを短く書くことができます。