homeASCIIcasts

8: Layouts and content_for 

(view original Railscast)

Other translations: It Es Fr

Below we have an application layout file and an index action:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
  <head>
    <title>Todo List</title>
    <%= stylesheet_link_tag 'application' %>
  </head>
  <body>
    <div id="container">
      <h1>Todo List</h1>
      <%= yield %>
    </div>
  </body>
</html>

application.rhtml[1]

<h2>Projects</h2>
<ul>
<% for project in @projects %>
  <li><%= project.name %></li>
<% end %>
</ul>

index.rhtml [1]

When the index action is rendered it will be rendered within the layout file. (See the previous episode for more details about layouts). But what if we want more control over the layout and want to customize it based on the template that is being rendered? Let’s say that we want to use a custom CSS file in the index template. The solution is to use a helper method called content_for in our template. content_for takes a symbol as an identifier, in this case :head, and a block. The code placed inside of the block will be stored for later use and not output inside the template.

<% content_for :head do %>
  <%= stylesheet_link_tag 'projects' %>
<% end %>
<h2>Projects</h2>
<ul>
<% for project in @projects %>
  <li><%= project.name %></li>
<% end %>
</ul>

index.rhtml[1]

This change won’t make any difference on its own as we’re not outputting the contents of the content_for. What we need to do next is to output the content somewhere in the layout. This can be done by calling yield with the symbol we gave the content_for. So by adding yield :head in an ERB block to the head section of our layout, the code within the content_for :head block in our template will be rendered there.

  …
  <head>
    <title>Todo List</title>
    <%= stylesheet_link_tag 'project' %>
    <%= yield :head %>
  </head>
  …

Looking at the source of the page we can now see the stylesheet reference in our content_for block has been added to the page.

The page's source with the stylesheet added

content_for provides a really useful way of changing the content of a layout dependent on the action. As well as adding stylesheets it can be used to show menus, sidebars or any other content we want only to appear in certain actions.

Notes

  1. For Rails 2 and above the extension should be .html.erb rather than .rhtml.