Written by: steve ross on November 12th 2008
Many Rails developers will create a default layout in application.html.erb and use it as a consistent wrapper for all pages rendered on a site. This is one of the cool features of Rails - consistent rendering of the site's layout. But what if you want to change things for certain controllers or actions.
Layouts By Controller
This is the trivial case because all you need to do is:
class AdminController < Application layout 'admin' def some_action end end
and every action within AdminController uses admin.html.erb instead of application.html.erb. But how about a controller that handles some public-facing and some administrative aspects?
Layouts With Exceptions
At first blush, this would also appear to be trivial. Just modify the code above as follows:
class AdminController < Application layout 'admin', :only => [:some_action] def some_action end def some_public_facing_action end end
At first glance this is flawless, and of course you're testing the action you changed, so you got suckered in. One day, you go to /some_public_facing_action and WTF?? There is no layout at all.
It turns out that what the line
layout 'admin', :only => [:some_action]
really means is apply the 'admin' layout to
some_action and don't apply any layout to anything else. So you think, well, How's about:
class AdminController < Application layout 'admin', :only => [:some_action] def some_action end def some_public_facing_action render :layout => 'application' end end
Bzzzt! Wrong answer. Rails already believes the public facing action is exempt from layout.
Using More Than One Layout in A Controller
The best way I've found to do this is to write a helper that determines on an individual basis which methods require which layout. Here's how:
class AdminController < Application
def some_action end def some_public_facing_action render :layout => 'application' end protected def smart_layout admin_actions = [:some_action] admin_actions.include?(action_name) ? 'admin' : 'application' end end
You may notice that I have only one action in my array, but more commonly, there will be multiple actions.
See Rails Guides for an in depth discussion of how layouts are inherited and controlled.