Skip to content

How To: Create custom layouts

Amin Shah Gilani edited this page Apr 30, 2016 · 22 revisions

If you simply want to use a custom layout across every Devise views, you can simply create a layout and name it devise.html.erb.

If you would like be more specific about how your custom layouts for Devise, you have two main options:

  1. Define layouts in the Controller
  2. Define layouts in the ApplicationController
  3. Define layouts in config (config/environment.rb for rails 2, config/application.rb in rails 3)

Define in Controller

The laziest method is to add a layout definition to the top of the controller and limit it to the needed action:

class User::RegistrationsController < Devise::RegistrationsController
  layout 'dashboard', only: [:edit]

  def edit
    super
  end
end

Define in ApplicationController

By using the devise_controller? helper you can determine when a Devise controller is active and respond accordingly. To have Devise use a separate layout to the rest of your application, you could do something like this:

class ApplicationController < ActionController::Base
  layout :layout_by_resource

  protected

  def layout_by_resource
    if devise_controller?
      "layout_name_for_devise"
    else
      "application"
    end
  end
end

You can build upon this to set a layout per role (or even per action). Below, resource_name is used to detect when Devise is handling an admin.

layout :layout_by_resource

protected

def layout_by_resource
  if devise_controller? && resource_name == :admin
    "layout_name_for_devise_admin"
  else
    "application"
  end
end

Here is an example of a layout by action

layout :layout_by_resource

protected

def layout_by_resource
  if devise_controller? && resource_name == :user && action_name == "new"
    "layout_name_for_devise"
  else
    "application"
  end
end

Note that if you have a devise.html.erb layout, it will take precedence over a layout specified in ApplicationController.

Define in config

You can also set the layout for specific Devise controllers using a callback in config/environment.rb (rails 2) or config/application.rb (rails 3). This needs to be done in a to_prepare callback because it's executed once in production and before each request in development.

This allows for layouts to be specified on a per-controller basis. If, for example, you want a specific layout assigned to Devise::SessionsController views:

config.to_prepare do
  Devise::SessionsController.layout "layout_for_sessions_controller" 
end

Or to configure the email layout:

config.to_prepare do
  Devise::Mailer.layout "email" # email.haml or email.erb
end

If you want the same layout for all Devise views, except for when the user is editing its data, you could have something like this:

config.to_prepare do
  Devise::SessionsController.layout "devise"
  Devise::RegistrationsController.layout proc{ |controller| user_signed_in? ? "application" : "devise" }
  Devise::ConfirmationsController.layout "devise"
  Devise::UnlocksController.layout "devise"            
  Devise::PasswordsController.layout "devise"        
end

If you prefer to put all config stuff in devise.rb config file:

# append to end of config/initializers/devise.rb
Rails.application.config.to_prepare do
  Devise::SessionsController.layout "devise"
  Devise::RegistrationsController.layout proc { |controller| user_signed_in? ? "application" : "devise" }
  Devise::ConfirmationsController.layout "devise"
  Devise::UnlocksController.layout "devise"
  Devise::PasswordsController.layout "devise"
end
Clone this wiki locally