Switch_off Switch_on Switch_off
Inventive Labs: Web Problem Solvers

Providing default content in Rails layouts [04092007]

Another quick tip for Rails view developers. We commonly employ the following snippet in our layouts:

<%= (out=yield :sidebar) ? out : render(:partial => 'sidebar') %>

This thorny little one-liner says, if the view we're rendering for this layout has content_for :sidebar, show that content. Otherwise show the default content (which we've tucked away in the 'sidebar' partial).

It's a handy pattern because it lets your views opt to modify some aspect of the layout, without having to — they can go with the default sidebar content if they don't care.

However. Firstly, it's a bit unsightly. Secondly, you must put the default content in a partial (unless it's short enough to just be a string — an approach that is arguably uglier). In most cases, the default content for a block in a layout is best described in that layout, so that you don't have to go hunting down other files to get a picture of what the layout displays. Here's a better way:

<% default_content_for :sidebar do %>
  <p>This is the default sidebar content! (et cetera)</p>
<% end %>

So now, if the view specifies some content_for :sidebar, the contents of the block above (ie, the <p> tag) will not be rendered. If the view doesn't do that, then the layout will render the contents of the block.

If you'd prefer this idiom in your views, drop the following method into application_helper.rb:

def default_content_for(name, &block)
  name = name.kind_of?(Symbol) ? ":#{name}" : name
  out = eval("yield #{name}", block.binding)
  concat(out || capture(&block), block.binding)
end

This method is full of bindings and captures, which you can read up on at your leisure, or feel free to ask questions in the comments.


Andy Stewart [Tue 26 Feb 2008, 9:21PM] said:

Elegant! It keeps the default content where it naturally belongs and makes the source immediately understandable.

Joseph Wilk [Thu 3 Jul 2008, 7:18PM] said:

Thanks, the 'defaultcontentfor' is exactly what I was looking for. Keeping the default text in the layout really helps prevent spaghetti templates.

Stephen Reid [Wed 19 Nov 2008, 6:37AM] said:

Great tip, thanks.

Scott Andreas [Sat 15 Aug 2009, 3:49AM] said:

Thanks for the tips, here - just found these pretty helpful in cleaning up the application layout of project I'm working on.

  • Scott
Keith [Tue 18 May 2010, 8:04PM] said:

There’s an easier way of course….

This is ruby after all…

<%= yield :sidebar || render(:partial => ‘sidebar’) %>

Will do the trick nicely :)

Joseph [Tue 18 May 2010, 8:10PM] said:

That definitely works, Keith. Is it as declarative as saying “Here’s the default content, right in this block”?

Up to you. Arguing over code aesthetics is a mug’s game.

Incidentally, the default_content_for method can be made a bit simpler now that concat no longer requires a binding.

Only the comment field is required. Omitting the ID fields increases your risk of being mistaken for spam.

Preview or