# Nested layouts?

**URL:** <https://www.ruby-forum.com/t/nested-layouts/67236>\
**Category:** Radiant CMS\
**Created:** [September 1, 2006, 3:36pm UTC](https://www.ruby-forum.com/t/nested-layouts/67236 "2006-09-01T15:36:23Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![keltia](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/da6949/32.png) [@keltia](https://www.ruby-forum.com/u/keltia)\
**Post date:** [September 1, 2006, 3:36pm UTC](https://www.ruby-forum.com/t/nested-layouts/67236/1 "2006-09-01T15:36:23Z")

</div>

Hello,

Is it possible to have some kind of nested layouts (like partials in  
Rails proper)?

Example: I have a page with a given layout. it has 3 parts, Body with

* * *

-----

and the two other parts (Main & Left) being the ones with content.  
The thing is, if I want to have another page with the schema, the  
content of Body must be deplicated in the new page to get the same  
layout.

The goal is to have what is in Body as a kind of template while still  
inheriting the “global” layout itself (which define css and snippets  
and all that).

Is it possible? Did I missed something obvious in the architecture?

Thanks,

---

<div class="post-metadata">

**Author:** ![keltia](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/da6949/32.png) [@keltia](https://www.ruby-forum.com/u/keltia)\
**Post date:** [September 1, 2006, 3:50pm UTC](https://www.ruby-forum.com/t/nested-layouts/67236/2 "2006-09-01T15:50:25Z")

</div>

Ollivier R. wrote:

> Is it possible to have some kind of nested layouts (like partials in  
> Rails proper)?

I’m having trouble visualizing how that would work. Can you show me how  
you would visualize a layout which used another layout?

–  
John L.  
[http://wiseheartdesign.com](http://wiseheartdesign.com)

---

<div class="post-metadata">

**Author:** ![keltia](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/da6949/32.png) [@keltia](https://www.ruby-forum.com/u/keltia)\
**Post date:** [September 1, 2006, 3:58pm UTC](https://www.ruby-forum.com/t/nested-layouts/67236/3 "2006-09-01T15:58:26Z")

</div>

On 9/1/06, John W. Long [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> I’m having trouble visualizing how that would work. Can you show me how  
> you would visualize a layout which used another layout?

I’m more looking at a way to render partials or template.

For the moment, I have

/ – (layout: plain)  
|  
±- page1  
| |  
| ±- body (layout: two-colums)  
| ±- left  
| ±- main  
|  
±- page2  
| |  
| ±- body (layout: two-colums)  
| ±- left  
| ±- main

If I need to add a page that will look like page1 or page2, I have to  
duplicate the “body” part.

What I’d like to say is: here is that page with layout “foo” but of  
type “bar”, being of type “bar” means that it will have two parts, one  
named “left” and the other “main”.

i.e. don’t duplicate the code in “body”.

The analogy being in Rails, you have the layout and partials.

Is that better?

Maybe I’m misunderstanding the radiant way to do it…

---

<div class="post-metadata">

**Author:** ![keltia](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/da6949/32.png) [@keltia](https://www.ruby-forum.com/u/keltia)\
**Post date:** [September 1, 2006, 5:48pm UTC](https://www.ruby-forum.com/t/nested-layouts/67236/4 "2006-09-01T17:48:48Z")

</div>

Can you not have the same result simply by having a “body” page\_part in  
the  
, and then not have a “body” page\_part in the actual pages. Radiant  
will  
look for the page\_part either in the page you are trying to show or in  
its  
parent.

If you need a different “body” for your root, then just create a hidden  
page  
with the “” slug put your template in the “body” page\_part, and create  
your  
pages under tis hidden page.

Dror

---

<div class="post-metadata">

**Author:** ![keltia](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/da6949/32.png) [@keltia](https://www.ruby-forum.com/u/keltia)\
**Post date:** [September 1, 2006, 4:06pm UTC](https://www.ruby-forum.com/t/nested-layouts/67236/5 "2006-09-01T16:06:27Z")

</div>

Ollivier,

Did you consider creating two layouts, one plain and one two-column? I  
understand it’s not the prettiest answer, but the 80% rule might apply  
in  
this case.

Another alternative would be to use some branching tags like  
“if\_content” or  
“if\_url” to determine which sub-layout to use, and use a snippet to  
encapsulate that sub-layout piece.

Sean C.  
[seancribbs.com](http://seancribbs.com)

---

<div class="post-metadata">

**Author:** ![keltia](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/da6949/32.png) [@keltia](https://www.ruby-forum.com/u/keltia)\
**Post date:** [January 24, 2008, 3:03pm UTC](https://www.ruby-forum.com/t/nested-layouts/67236/6 "2008-01-24T15:03:08Z")

</div>

That’s an interesting solution, in principle similar to the solution I  
had for the same problem. However, there are some very un-Rails-ish  
statements in your tag implementation that make your intentions  
unclear. For example, you find PageParts by their page\_id, when really  
you should use the existing association:

ancestor\_part\_names = ancestor.parts.map(&:name)

Next, you use Array.detect where include? will suffice:

if ancestor\_part\_names.include?(layout\_name)

Radiant’s page model offers a shortcut method to getting a part by name,  
so your next detect call is also unneeded. In fact this whole block of  
statements can be replaced by one line:

tag.locals.page = ancestor if ancestor.part(layout\_name)

Page#part will return nil if no matching part is found. Better yet, use  
find/detect instead of each:

tag.locals.page = page.ancestors.find {|p| p.part(layout\_name) }

There are several other things in your tag definitions that could use  
attention, I’ll probably make a pass at them later.

Sean

---

<div class="post-metadata">

**Author:** ![keltia](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/da6949/32.png) [@keltia](https://www.ruby-forum.com/u/keltia)\
**Post date:** [January 25, 2008, 10:02am UTC](https://www.ruby-forum.com/t/nested-layouts/67236/7 "2008-01-25T10:02:04Z")

</div>

Thank you very much, Sean.

To all interested here is a cleaned up version of r:layout

```
tag 'layout' do |tag|
    layout_name = tag.attr['layout_name'] || "layout"
    page = tag.locals.page
    page_part_names = page.parts.collect(&:name)
    parts_for_layout = tag.attr['parts'] || 

```

page\_part\_names.collect{|part| part != “body” || part != layout\_name }  
og\_page\_id = page.id  
tag.locals.page = page.ancestors.find{|p| p.part(layout\_name) }  
if !page\_part\_names.include? layout\_name  
tag.render(‘content’, {“part” =\> layout\_name, “parts\_page\_id” =\>  
og\_page\_id})  
end

---

<div class="post-metadata">

**Author:** ![keltia](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/da6949/32.png) [@keltia](https://www.ruby-forum.com/u/keltia)\
**Post date:** [January 24, 2008, 7:36am UTC](https://www.ruby-forum.com/t/nested-layouts/67236/8 "2008-01-24T07:36:13Z")

</div>

I have revived this post in order to get comments on my implementation  
of nested layouts. I created custom tags to allow for this. Here is my  
solution to the scenario given above.

First, in “/”, create a page part called “layout” to be used as the  
nested layout. It will look like this:

\<r:layout\_part name=“left”\>

\<r:layout\_part name=“main”\>

Then edit the “body” page part of “page1” and “page2” to look like this:

\<r:layout /\>

The code behind r:layout and r:layout\_part follows:

* * *

```
# the layout is actually a page part
# if the named page part is not a part of the current page
# ancestors are searched until the named page part is found
tag 'layout' do |tag|
    ret_val = ""
    layout_name = tag.attr['layout_name'] || "layout"
    page = tag.locals.page
    page_part_names = 

```

page.instance\_variable\_get(:@parts).collect(&:name)  
parts\_for\_layout = tag.attr[‘parts’] ||  
page\_part\_names.delete\_if{|part| part == “body” || part == layout\_name }  
found = nil  
og\_page\_id = page.id  
if !page\_part\_names.include? layout\_name  
page.ancestors.each do |ancestor|  
pp =  
PagePart.find\_all\_by\_page\_id(ancestor.instance\_variable\_get(:@attributes)[“id”],  
:include =\> [:page])  
ancestor\_part\_names = pp.collect(&:name)  
if ancestor\_part\_names.detect{|part| part == layout\_name  
} && !found  
tag.locals.page = pp.detect{|p| p.name ==  
layout\_name}.page  
found = 1  
end  
end  
tag.render(‘content’, {“part” =\> layout\_name,  
“parts\_page\_id” =\> og\_page\_id})  
else  
tag.render(‘content’, {“part” =\> layout\_name})  
end  
end

```
tag 'layout_part' do |tag|
    part_to_render = tag.attr['name']

    # this mess is necessary; trying to get tag_binding_stack 

```

directly from the context returns a different array  
page = tag.locals.page  
response = page.instance\_variable\_get(:@response)  
template = response.instance\_variable\_get(:@template)  
controller = template.instance\_variable\_get(:@controller)  
pagee = controller.instance\_variable\_get(:@page)  
context = pagee.instance\_variable\_get(:@context)  
tbs = context.instance\_variable\_get(:@tag\_binding\_stack)

```
    parts_page_id = tbs.last.attributes["parts_page_id"]

    # if the layout is in the same page as the parts being laid out
    # the parts_page_id will not have been specified, so do not 

```

reset the tag page  
unless parts\_page\_id.blank?  
parts\_page = Page.find(parts\_page\_id)  
tag.locals.page = parts\_page  
end

```
    # e.g. name of part is specified in the tag as 'blah'
    # but the page calling the layout tag which wraps this tag does 

```

not have a ‘blah’ part  
# in such a case don’t display this tag  
# NOTE: there is likely a more efficient way to do this check  
than a db query  
pp = PagePart.find\_by\_name\_and\_page\_id(part\_to\_render,  
parts\_page\_id || tag.locals.page.id)  
tag.expand unless pp.blank?  
end

* * *

Thank you in advance for any criticism/comments.
