Nested Layouts 10

Posted by pratik
on Tuesday, July 07

Don’t think the nested layouts get any simpler in Rails.

1
2
3
4
5
6
module ApplicationHelper
  def parent_layout(layout)
    @content_for_layout = self.output_buffer
    self.output_buffer = render(:file => "layouts/#{layout}")
  end
end

Now using the parent_layout helper method inside your layouts for nesting :

1
2
3
4
5
# items.html.erb
<h1>Just my items</h1>
<%= yield %>

<% parent_layout 'master' %>

and the parent layout of items – the master layout :

1
2
3
4
5
6
7
# master.html.erb
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head><title>Hello World</title></head>
  <body>
    <%= yield %>
  </body>
</html>

Now, the items layout will always be wrapped under the master layout. Just make sure that the parent_layout call is always on the last line using <%. This technique also works for nesting deeper than a single level.

Comments

Leave a response

  1. Ben JohnsonJuly 07, 2009 @ 11:43 PM

    Nice post, not sure if you’ve seen this or not.

    http://pastie.org/537822

    But I’ve been using this for years and its worked out great. The syntax is a little different though:

    <% inside_layout 'base' do %>
    my content
    <%= yield %>
    <% end %>
    
  2. Steven BristolJuly 08, 2009 @ 12:04 AM

    Nice, but I think in general, if you need to do this, you’ve already made a mistake higher up in the stack. (Doesn’t mean I don’t love you.)

  3. Jon SidnellJuly 08, 2009 @ 01:06 AM

    Thank you! I’ve been looking for a technique like this for some time now :)

    I’ll give it a try next time I’m building something in Rails!

  4. Kyle CrumJuly 08, 2009 @ 07:39 AM

    I don’t understand why this would ever be needed, especially when there is a layout parameter to the render method. Any template that you render, whether it’s a partial or not, can be wrapped in a layout, which means you can have as many layouts within a page as you want.

  5. PratikJuly 08, 2009 @ 09:23 AM

    @Steve lol! My main use case is for admin layouts, where I have to add some menu on the top/bottom to the regular application layout.

    @Kyle Partial layouts are slightly different.

    @Ben Yeah I had seen that again. Still find my solution more elegant :P Yours is more flexible though.

  6. BotanicusJuly 08, 2009 @ 12:59 PM

    Nice, but I personaly prefer template inheritance (I hope this is basically what is your post about) (great description at Django docs: http://docs.djangoproject.com/en/dev/topics/templates/#template-inheritance). I implement it in my tiny rack-based framework called Rango: http://github.com/botanicus/rango … and here is showcase: http://gist.github.com/88171 ATM no more docs, it’s in quite early stage of development (but already works nice and fast).

  7. Insane DreamerDecember 01, 2009 @ 03:40 AM

    How is this better than just putting <% render :file => ‘layouts/master’ %> in the “inner” layout, and eliminate the need for one more helper?

  8. LukeJanuary 03, 2010 @ 02:26 AM

    @Insane Dreamer: because Pratik’s solution captures everything in the “inner” layout and passes it to the yield statement in the “outer” layout. Otherwise, the content just sits on top of the layout… unless, of course, you explicitly surround it with <% content_for(:layout) do >[...]< end %>

    Thanks for posting this, btw.

  9. twingeFebruary 07, 2010 @ 08:45 PM

    Trying this in Rails 3 I get a “no block given” error. Any chance you might have an update for us? Thx

  10. Andrew WatkinsMarch 08, 2010 @ 05:38 PM

    I also get the same errors with Rails 3, can anyone else shed light on how to approach it?

Comment