I'm having trouble finding a way to do the following:
Let's say in my application.html.erb I have the following
<div id="one" >
<%= yield %>
</div>
Then I want to have another layout file asdf.html.erb
<div id="two">
<%= yield %>
</div>
I want the final output to be
<div id="one">
<div id="two">
<%= yield %>
</div>
</div>
Is it possible? Thanks.
A generated Rails application has a default layout and it’s defined in the app/views/layouts/application.html.erb. On the screen above there is only one dynamic block - it’s the body, the footer, the header and the sidebar are common blocks for each page.
When Rails renders a view as a response, it does so by combining the view with the current layout, using the rules for finding the current layout that were covered earlier in this guide. Within a layout, you have access to three tools for combining different bits of output to form the overall response:
You can use the :layout option to tell Rails to use a specific file as the layout for the current action: You can also tell Rails to render with no layout at all: You can use the :location option to set the HTTP Location header: Rails will automatically generate a response with the correct HTTP status code (in most cases, this is 200 OK ).
As you see each of these three steps includes common blocks: they are the progress bar, the “Submit” button and when you start to implement the steps you will see that it contains repetitive code. It may be, for example, form tags. This is the problem of nested layout.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With