Unless someone can convince me otherwise, I hereby formally wish for nested layouts without using inheritance. For example:
class <span class="newWikiWord">FooController<a href="http://wiki.rubyonrails.org/rails/pages/FooController">?</a></span> < <a href="http://wiki.rubyonrails.org/rails/pages/ActionController" class="existingWikiWord">ActionController</a>::Base
layout 'layout/outside'
layout 'layout/inside'
end
Thoughts?
This is one of my wishes too.
Currently I handle this by wrapping a template that requires an inside layout with:
<% @content_for_inner_layout = capture do %>
and
<% end %>
<%= render 'layouts/inner_layout', { 'content_for_inner_layout' => @content_for_inner_layout } %>
Then do the actual wrapping of the template by including:
<%= @content_for_inner_layout %>
where it needs to be within the inner layout.
Is there a better way to handle this?
—-
I use a little bit of black magic that can be found in CaptureHelper (the way it manipulate output buffer):
module ActionView
module Helpers
module NestedLayoutsHelper
def inside_layout(layout, &block)
layout = layout.include?('/') ? layout : "layouts/#{layout}"
concat(@template.render_file(layout, true, '@content_for_layout' => capture(&block)), block.binding)
end
end
end
end
ActionView::Base.class_eval do
include ActionView::Helpers::NestedLayoutsHelper
end
In controller write
class FooController < ApplicationController layout 'inner' end
Then inside your ‘layouts/inner.rhtml’ do
<% inside_layout 'outer' do %> Inner layout header <%= @content_for_layout %> Inner layout footer <% end %>
The outer layout can also nest itself inside a higher level layout.
I took that idea from Microsoft ASP.NET v2.0 Master pages implementation: for every master page (that is “layout” in Rails terms) you can specify parent master page.
In my implementation it goes even further: the master page can be changed by changing the value of first parameter to “inside_layout” method. You can specify a method call there that will return the proper “outer” layout name.
— Maxim Kulkin
Corrected error in concat line
— Iktorn
I’ve beat my head over the same problem, though I took a different route. Since you have access to erbout in the views, you can build something to manipulate it.
content = _erbout.dup %>
<% pre
<= “stuff” %>
<= “more stuff” %>
<%
post_content = _erbout.dup
erbout = precontent
post_content.slice!(pre_content)
%>
<%= post_content %>
I made a plugin that wraps that up in a stack, so you can have nested buffers.
svn://ahgsoftware.com/erb_buffer/trunk
I tried in vain at finding a clean way to use the Erb capture method!
— MikeC
I use this method which allows me to infinitely nest layouts that at any given level can be used. By this I mean if you have layout 2 nested in layout 1 and layout 3 nested in layout 2, all 3 layouts are usable. Heres a concrete example.
application.rhtml:
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”
“http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
Title <%= stylesheet_link_tag “main”, :media => “all” %>
<%= yield :layout %>
inner.rhtml
<% @content_for_layout = capture do >
<= yield :layout %>
<% end >
<= render ‘layouts/application’, { ‘content_for_layout’ => @content_for_layout } %>
In this situation both ‘application’ and ‘inner’ are usable layouts.
The results of running render :text => ‘Hello World’, :layout => ‘inner’ would be:
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”
“http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
Title <%= stylesheet_link_tag “main”, :media => “all” %>
Hello World
_— David Genord II
Unless someone can convince me otherwise, I hereby formally wish for nested layouts without using inheritance. For example:
class <span class="newWikiWord">FooController<a href="http://wiki.rubyonrails.org/rails/pages/FooController">?</a></span> < <a href="http://wiki.rubyonrails.org/rails/pages/ActionController" class="existingWikiWord">ActionController</a>::Base
layout 'layout/outside'
layout 'layout/inside'
end
Thoughts?
This is one of my wishes too.
Currently I handle this by wrapping a template that requires an inside layout with:
<% @content_for_inner_layout = capture do %>
and
<% end %>
<%= render 'layouts/inner_layout', { 'content_for_inner_layout' => @content_for_inner_layout } %>
Then do the actual wrapping of the template by including:
<%= @content_for_inner_layout %>
where it needs to be within the inner layout.
Is there a better way to handle this?
—-
I use a little bit of black magic that can be found in CaptureHelper (the way it manipulate output buffer):
module ActionView
module Helpers
module NestedLayoutsHelper
def inside_layout(layout, &block)
layout = layout.include?('/') ? layout : "layouts/#{layout}"
concat(@template.render_file(layout, true, '@content_for_layout' => capture(&block)), block.binding)
end
end
end
end
ActionView::Base.class_eval do
include ActionView::Helpers::NestedLayoutsHelper
end
In controller write
class FooController < ApplicationController layout 'inner' end
Then inside your ‘layouts/inner.rhtml’ do
<% inside_layout 'outer' do %> Inner layout header <%= @content_for_layout %> Inner layout footer <% end %>
The outer layout can also nest itself inside a higher level layout.
I took that idea from Microsoft ASP.NET v2.0 Master pages implementation: for every master page (that is “layout” in Rails terms) you can specify parent master page.
In my implementation it goes even further: the master page can be changed by changing the value of first parameter to “inside_layout” method. You can specify a method call there that will return the proper “outer” layout name.
— Maxim Kulkin
Corrected error in concat line
— Iktorn
I’ve beat my head over the same problem, though I took a different route. Since you have access to erbout in the views, you can build something to manipulate it.
content = _erbout.dup %>
<% pre
<= “stuff” %>
<= “more stuff” %>
<%
post_content = _erbout.dup
erbout = precontent
post_content.slice!(pre_content)
%>
<%= post_content %>
I made a plugin that wraps that up in a stack, so you can have nested buffers.
svn://ahgsoftware.com/erb_buffer/trunk
I tried in vain at finding a clean way to use the Erb capture method!
— MikeC
I use this method which allows me to infinitely nest layouts that at any given level can be used. By this I mean if you have layout 2 nested in layout 1 and layout 3 nested in layout 2, all 3 layouts are usable. Heres a concrete example.
application.rhtml:
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”
“http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
Title <%= stylesheet_link_tag “main”, :media => “all” %>
<%= yield :layout %>
inner.rhtml
<% @content_for_layout = capture do >
<= yield :layout %>
<% end >
<= render ‘layouts/application’, { ‘content_for_layout’ => @content_for_layout } %>
In this situation both ‘application’ and ‘inner’ are usable layouts.
The results of running render :text => ‘Hello World’, :layout => ‘inner’ would be:
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”
“http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
Title <%= stylesheet_link_tag “main”, :media => “all” %>
Hello World
_— David Genord II