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.






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:
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.)
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!
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.
@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.
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).
How is this better than just putting <% render :file => ‘layouts/master’ %> in the “inner” layout, and eliminate the need for one more helper?
@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.
Trying this in Rails 3 I get a “no block given” error. Any chance you might have an update for us? Thx
I also get the same errors with Rails 3, can anyone else shed light on how to approach it?
The “no block given” error crops up in lib/action_view/render/rendering.rb in actionpack. The #_render_template method is failing to pass a block to template.render on line 101.
The problem appears to already be fixed in edge, but until then you could try this:
config/initializers/duck_punch_rendering.rb
require ‘active_support/core_ext/object/try’
module ActionView module Rendering endNotice the { |name| _layout_for(name) } block, which is the thing living on the other side of your template’s yields.
I haven’t tried it with #parent_layout, but it appears to work with the approach insane dreamer suggests:
Excuse me, I didn’t expect the formatting. See the same thing over at http://gist.github.com/339170
Here’s the rails3 compatible version (to date):
module ApplicationHelper def parent_layout(layout) @_content_for[:layout] = self.output_buffer self.output_buffer = render(:file => “layouts/#{layout}”) end end
Dmitry’s code works fine in Rails 3 using ERB but not with HAML. Does anybody know why?
@carson does: def inside_layout layout = ‘application’, &block render :inline => capture_haml(&block), :layout => “layouts/#{layout}” end
work for you?
@Dmitry your version works for me too. Cheers.