content_for
content_for(name, content = nil, &block)
public
Calling content_for stores a block of markup in an identifier for later use. You can make subsequent calls to the stored content in other templates or the layout by passing the identifier as an argument to yield.
Examples
<% content_for :not_authorized do %> alert('You are not authorized to do that!') <% end %>
You can then use yield :not_authorized anywhere in your templates.
<%= yield :not_authorized if current_user.nil? %>
You can also use this syntax alongside an existing call to yield in a layout. For example:
<%# This is the layout %> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <title>My Website</title> <%= yield :script %> </head> <body> <%= yield %> </body> </html>
And now, we’ll create a view that has a content_for call that creates the script identifier.
<%# This is our view %> Please login! <% content_for :script do %> <script type="text/javascript">alert('You are not authorized to view this page!')</script> <% end %>
Then, in another view, you could to do something like this:
<%= link_to_remote 'Logout', :action => 'logout' %> <% content_for :script do %> <%= javascript_include_tag :defaults %> <% end %>
That will place <script> tags for Prototype, Scriptaculous, and application.js (if it exists) on the page; this technique is useful if you’ll only be using these scripts in a few views.
Note that content_for concatenates the blocks it is given for a particular identifier in order. For example:
<% content_for :navigation do %> <li><%= link_to 'Home', :action => 'index' %></li> <% end %> <%# Add some other content, or use a different template: %> <% content_for :navigation do %> <li><%= link_to 'Login', :action => 'login' %></li> <% end %>
Then, in another template or layout, this code would render both links in order:
<ul><%= yield :navigation %></ul>
Lastly, simple content can be passed as a parameter:
<% content_for :script, javascript_include_tag(:defaults) %>
WARNING: content_for is ignored in caches. So you shouldn’t use it for elements that will be fragment cached.
The deprecated way of accessing a content_for block is to use an instance variable named @content_for_#{name_of_the_content_block}. So <%= content_for :footer %> would be available as <%= @content_for_footer %>. The preferred usage is now <%= yield :footer %>.
Clearing out previous values from content_for
By default, content_for :thing appends whatever you put in your block to the previous value of :thing. In some cases, you’d like to clear out :thing rather than append to it.
I just posted a way to do this on my blog: http://stevechanin.blogspot.com/2009/11/clearing-out-content-in-contentfor.html
I add a new method set_content_for that works just like content_for, but clears out :thing first. It doesn’t touch how content_for works, so it shouldn’t cause any problems anywhere else in your app.
Check content_for content
There is a content_for? method in Rails wherewith you can check the content. http://github.com/rails/rails/commit/9cb8c812f2a23ab5653a7888740a014a02c97c18#diff-1
But it’s not in the last stable version (2.3.5) http://github.com/rails/rails/blob/v2.3.5/actionpack/lib/action_view/helpers/capture_helper.rb
How to check if a Yield has content?
How do I do this without actually calling the yield?
- if yield :footer = yield :footer - else = render "layouts/footer_big"
(Note: HAML Syntax) Thanks.
Checking content_for
@tordans You asked your question 3 years ago, but in any case, should anyone have that same issue, you can manage that with:
- unless content_for(:footer).blank? yield(:footer) - else == render "layouts/footer_big"
content_for(:x) defaults to an empty string, that’s why you need to check for blank? not nil?.
Checking content_for
There’s a much simpler way to check if content exists or not, and it’s been provided as example in docs since 05.2010:
module StorageHelper def stored_content content_for(:storage) || "Your storage is empty" end end
But this behavior was broken with SafeBuffer. You’ll be able to use it again when this issue (github.com/rails/rails/issues/9360) will be fixed and merged with master.