AlmaConnect

Hi, We'are AlmaConnect.

Alma Connect provides alumni platform for your institute. You can request and check for your college network: visit www.almaconnect.com now.

Alma Connect

Layouts and rendering in rails

I came across this question on stackoverflow. There is an excellent guide out there about Layouts and Rendering which everyone should read. I would like to share a few tricks that can be used to support common scenarios.

Conditional Content in Layout

Lets start with a simple application.html:

 1 # app/views/layouts/application.html.erb
 2 <!DOCTYPE html>
 3 <html>
 4   <head>
 5     <!-- head content -->
 6   </head>
 7   <body>
 8     <%= render 'layouts/header' %>
 9     <%= yield %>
10   </body>
11 </html>

If header is shown only for some pages, rendering of header can be made conditional. It just requires a few modifications:

1 # app/controllers/application_controller.rb
2 class ApplicationController < ActionController::Base
3   attr_accessor :headless
4   helper_method :headless
5 
6   def show
7     self.headless = true
8   end
9 end
1 # app/views/layouts/application.html.erb
2 .....
3   <%= render('layouts/header') unless headless %>
4 .....

We defined an attribute headless and also declared the getter to be helpor method, to facilitate usage in views. headless is set to true if we do not want to show header on a page.

Multiple layouts

But that is not enough, registration and authenticated pages have a completely different layout. We cannot just keep adding conditionals. Lets create different layouts for our guests and users. We will keep application layout for users and create a new layout for guests.

 1 # app/views/layouts/application.html.erb
 2 <!DOCTYPE html>
 3 <html>
 4   <head>
 5     <!-- head content -->
 6   </head>
 7   <body>
 8     <%= render('layouts/header') unless headless %>
 9     <div class="page">
10       <%= render 'layouts/sidebar' %>
11 
12       <div class="page-content">
13         <%= yield %>
14       </div>
15     </div>
16   </body>
17 </html>
 1 # app/views/layouts/guest.html.erb
 2 <!DOCTYPE html>
 3 <html>
 4   <head>
 5     <!-- head content -->
 6   </head>
 7   <body>
 8     <%= render 'layouts/login_bar' %>
 9     <%= yield %>
10   </body>
11 </html>
 1 # app/controllers/guest_controller.rb
 2 class GuestController < ApplicationController
 3   # change layout for all controller actions 
 4   layout 'guest'
 5 
 6   def signin
 7   end
 8 
 9   def signup
10     # change layout on per action basis
11     render layout: 'guest'
12   end
13 end

Layout can be configured on a controller level or per action level. If set on a controller level, all the actions of controller will use that layout.

Common head in multiple layouts

Head content in both the layouts is common, why don't we extract it out in a partial. Extracting head content in a partial is trivial, but what if we want to extract out doctype and html tag as well? Worry not, partial layouts to the rescue.

 1 # app/views/layouts/_head.html.erb
 2 <!DOCTYPE html>
 3 <html>
 4   <head>
 5     <!-- head content -->
 6   </head>
 7   <body>
 8     <%= yield %>
 9 
10     <%= render 'layouts/footer' %>
11   </body>
12 </html>
 1 # app/views/layouts/application.html.erb
 2 <%= render :layout => 'layouts/head' do %>
 3 
 4   <%= render('layouts/header') unless headless %>
 5   <div class="page">
 6     <%= render 'layouts/sidebar' %>
 7 
 8     <div class="page-content">
 9       <%= yield %>
10     </div>
11   </div>
12 
13 <% end # render partial layout 'head' %>
1 # app/views/layouts/guest.html.erb
2 <%= render :layout => 'layouts/head' do %>
3 
4   <%= render 'layouts/login_bar' %>
5   <%= yield %>        
6 
7 <% end # render partial layout 'head' %>

Now we don't have to worry about making changes in multiple layouts when we change head.

Page specific assets

Now that we have one layout each for our guests and users, we can also saperate out our assets for the layouts. We can have template specific assets as well. content_for is apt for this.

 1 # app/views/layouts/_head.html.erb
 2 <!DOCTYPE html>
 3 <html>
 4   <head>
 5     <!-- head content -->
 6 
 7     <%= yield :layout_assets %>
 8     <%= yield :template_assets %>
 9   </head>
10   <body>
11     <%= yield %>
12 
13     <%= render 'layouts/footer' %>
14   </body>
15 </html>
 1 # app/views/layouts/guest.html.erb
 2 <%= render :layout => 'layouts/head' do %>
 3   <% content_for :layout_assets do %>
 4     <!-- layout specific assets -->
 5   <% end %>
 6 
 7   <%= render 'layouts/login_bar' %>
 8   <%= yield %>        
 9 
10 <% end # render partial layout 'head' %>
1 # app/views/guest/login.html.erb
2 <% content_for :template_assets do %>
3   <!-- template specific assets -->
4 <% end %> 
5 
6 <!-- template content -->

I hope this was useful imformation for some. If you have any tricks, please share in comments.