Nested Layouts in Rails Nested Layouts in Rails ruby-on-rails ruby-on-rails

Nested Layouts in Rails


The cleanest solution I found by far came from this repo : https://github.com/rwz/nestive

I did not want the whole gem. If you're like me, here's how I achieved what I wanted:

# application_helper.rb  # From https://github.com/rwz/nestive/blob/master/lib/nestive/layout_helper.rb  def extends(layout, &block)    # Make sure it's a string    layout = layout.to_s    # If there's no directory component, presume a plain layout name    layout = "layouts/#{layout}" unless layout.include?('/')    # Capture the content to be placed inside the extended layout    @view_flow.get(:layout).replace capture(&block)    render file: layout  end

Then you keep /layouts/application.html.erb unchanged!

And you can create other layouts. In my case /layouts/public.html.erb and /layouts/devise.html.erb:

# public.html.erb<%= extends :application do %>  <%= render 'partials/navbar' %>  <div class="container margin-top">    <%= yield %>  </div><% end %># devise.html.erb<%= extends :public do %>  <div class="col-sm-6 col-sm-offset-3">    <%= yield %>  </div><% end %>

Works like a charm! I am still smiling I finally found a clean solution.


By default, application.html.erb is your layout. You can render a default sub-layout by calling it as a partial from your application layout:

# app/views/layouts/application.html.erb<div id="one" >    <%= render "layouts/asdf" %></div># app/views/layouts/_asdf.html.erb<div id="two">    <%= yield %></div>

This will output the following:

<div id="one>   <div id="two">      <%= yield %>   </div></div>

Alternatively, if you're looking to conditionally render layouts on a controller-by-controller basis, you should consider using nested layouts. From the documentation:

On pages generated by NewsController, you want to hide the top menu and add a right menu:

# app/views/layouts/news.html.erb<% content_for :stylesheets do %>  #top_menu {display: none}  #right_menu {float: right; background-color: yellow; color: black}<% end %><% content_for :content do %>  <div id="right_menu">Right menu items here</div>  <%= content_for?(:news_content) ? yield(:news_content) : yield %><% end %><%= render template: "layouts/application" %>

The News views will use the new layout, hiding the top menu and adding a new right menu inside the "content" div.


Rename asdf.html.erb to _asdf.html.erb and rewrite application.html.erb to this:

<div id="one">  <%= render 'asdf' %></div>

More about partials here: http://guides.rubyonrails.org/layouts_and_rendering.html#using-partials