# module AbstractController::Layouts

Layouts reverse the common pattern of including shared headers and footers in many templates to isolate changes in repeated setups. The inclusion pattern has pages that look like this:

    <%= render "shared/header" %>
    Hello World
    <%= render "shared/footer" %>

This approach is a decent way of keeping common structures isolated from the changing content, but it’s verbose and if you ever want to change the structure of these two includes, you’ll have to change all the templates.

With layouts, you can flip it around and have the common structure know where to insert changing content. This means that the header and footer are only mentioned in one place, like this:

    // The header part of this layout
    <%= yield %>
    // The footer part of this layout

And then you have content pages that look like this:

    hello world

At rendering time, the content page is computed and then inserted in the layout, like this:

    // The header part of this layout
    hello world
    // The footer part of this layout

## Accessing shared variables¶ ↑

Layouts have access to variables specified in the content pages and vice versa. This allows you to have layouts with references that won't materialize before rendering time:

    <h1><%= @page_title %></h1>
    <%= yield %>

…and content pages that fulfill these references at rendering time:

    <% @page_title = "Welcome" %>
    Off-world colonies offers you a chance to start a new life

The result after rendering is:

    <h1>Welcome</h1>
    Off-world colonies offers you a chance to start a new life

## Layout assignment¶ ↑

You can either specify a layout declaratively (using the layout class method) or give it the same name as your controller, and place it in `app/views/layouts`. If a subclass does not have a layout specified, it inherits its layout using normal Ruby inheritance.

For instance, if you have PostsController and a template named `app/views/layouts/posts.html.erb`, that template will be used for all actions in PostsController and controllers inheriting from PostsController.

If you use a module, for instance Weblog::PostsController, you will need a template named `app/views/layouts/weblog/posts.html.erb`.

Since all your controllers inherit from ApplicationController, they will use `app/views/layouts/application.html.erb` if no other layout is specified or provided.

## Inheritance Examples¶ ↑

    class BankController < ActionController::Base
      # bank.html.erb exists

    class ExchangeController < BankController
      # exchange.html.erb exists

    class CurrencyController < BankController

    class InformationController < BankController
      layout "information"

    class TellerController < InformationController
      # teller.html.erb exists

    class EmployeeController < InformationController
      # employee.html.erb exists
      layout nil

    class VaultController < BankController
      layout :access_level_layout

    class TillController < BankController
      layout false

In these examples, we have three implicit lookup scenrios:

- The BankController uses the “bank” layout.

- The ExchangeController uses the “exchange” layout.

- The CurrencyController inherits the layout from BankController.

However, when a layout is explicitly set, the explicitly set layout wins:

- The InformationController uses the “information” layout, explicitly set.

- The TellerController also uses the “information” layout, because the parent explicitly set it.

- The EmployeeController uses the “employee” layout, because it set the layout to nil, resetting the parent configuration.

- The VaultController chooses a layout dynamically by calling the `access_level_layout` method.

- The TillController does not use a layout at all.

## Types of layouts¶ ↑

Layouts are basically just regular templates, but the name of this template needs not be specified statically. Sometimes you want to alternate layouts depending on runtime information, such as whether someone is logged in or not. This can be done either by specifying a method reference as a symbol or using an inline method (as a proc).

The method reference is the preferred approach to variable layouts and is used like this:

    class WeblogController < ActionController::Base
      layout :writers_and_readers

      def index
        # fetching posts
      end

      private
        def writers_and_readers
          logged_in? ? "writer_layout" : "reader_layout"
        end

Now when a new request for the index action is processed, the layout will vary depending on whether the person accessing is logged in or not.

If you want to use an inline method, such as a proc, do something like this:

    class WeblogController < ActionController::Base
      layout proc{ |controller| controller.logged_in? ? "writer_layout" : "reader_layout" }
    end

Of course, the most common way of specifying a layout is still just as a plain template name:

    class WeblogController < ActionController::Base
      layout "weblog_standard"
    end

If no directory is specified for the template name, the template will by default be looked for in `app/views/layouts/`. Otherwise, it will be looked up relative to the template root.

Setting the layout to nil forces it to be looked up in the filesystem and fallbacks to the parent behavior if none exists. Setting it to nil is useful to re-enable template lookup overriding a previous configuration set in the parent:

    class ApplicationController < ActionController::Base
      layout "application"
    end

    class PostsController < ApplicationController
      # Will use "application" layout
    end

    class CommentsController < ApplicationController
      # Will search for "comments" layout and fallback "application" layout
      layout nil
    end

## Conditional layouts¶ ↑

If you have a layout that by default is applied to all the actions of a controller, you still have the option of rendering a given action or set of actions without a layout, or restricting a layout to only a single action or a set of actions. The `:only` and `:except` options can be passed to the layout call. For example:

    class WeblogController < ActionController::Base
      layout "weblog_standard", :except => :rss

      # ...

    end

This will assign “weblog_standard” as the WeblogController’s layout for all actions except for the `rss` action, which will be rendered directly, without wrapping a layout around the rendered view.

Both the `:only` and `:except` condition can accept an arbitrary number of method references, so #`:except => [ :rss, :text_only ]` is valid, as is `:except => :rss`.

## Using a different layout in the action render call¶ ↑

If most of your actions use the same layout, it makes perfect sense to define a controller-wide layout as described above. Sometimes you’ll have exceptions where one action wants to use a different layout than the rest of the controller. You can do this by passing a `:layout` option to the `render` call. For example:

    class WeblogController < ActionController::Base
      layout "weblog_standard"

      def help
        render :action => "help", :layout => "help"
      end
    end

This will override the controller-wide “weblog_standard” layout, and will render the help action with the “help” layout instead.

### Public Class Methods

new(*) click to toggle source
Calls superclass method

    # File lib/abstract_controller/layouts.rb, line 356
    def initialize(*)
      @_action_has_layout = true
      super
    end

### Public Instance Methods

_normalize_options(options) click to toggle source
Calls superclass method

    # File lib/abstract_controller/layouts.rb, line 345
    def _normalize_options(options)
      super

      if _include_layout?(options)
        layout = options.key?(:layout) ? options.delete(:layout) : :default
        options[:layout] = _layout_for_option(layout)
      end
    end

action_has_layout?() click to toggle source

    # File lib/abstract_controller/layouts.rb, line 361
    def action_has_layout?
      @_action_has_layout
    end

conditional_layout?() click to toggle source

    # File lib/abstract_controller/layouts.rb, line 365
    def conditional_layout?
      true
    end