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