How To: Create custom layouts

Brendan Benson edited this page Mar 12, 2018 · 19 revisions

If you would like to use a custom layout or layouts for Devise views, you have the following options:

  1. Use layout in individual Controllers
  2. Use layout and devise_controller? in ApplicationController
  3. Configure layouts for individual controllers in config/application.rb

Individual Controller

The easiest method is to provide your own controller as a subclass of a Devise controller and override the layout in the conventional Rails way:

# With custom single controller
class User::RegistrationsController < Devise::RegistrationsController
  layout "devise", only: [:edit]
end

# With custom Devise parent controller
# config/initializers/devise.rb
config.parent_controller = 'MyBaseDeviseController'

# Controller
class MyBaseDeviseController < ApplicationController
  layout "devise"
end

ApplicationController

By using the devise_controller? helper you can determine when a Devise controller is active and override the layout accordingly:

class ApplicationController < ActionController::Base
  layout :layout_by_resource

  private

  def layout_by_resource
    if devise_controller?
      "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 per resource_name
def layout_by_resource
  if devise_controller? && resource_name == :admin
    "layout_name_for_devise_admin"
  else
    "application"
  end
end

# Layout per resource_name AND action
def layout_by_resource
  if devise_controller? && resource_name == :user && action_name == "new"
    "layout_name_for_devise"
  else
    "application"
  end
end

Application / Devise Config

You can also set the layout for specific Devise controllers using a callback in config/application.rb. 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
  # Configure single controller layout
  Devise::SessionsController.layout "layout_for_sessions_controller"

  # Or to configure mailer layout
  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::RegistrationsController.layout proc { |controller| user_signed_in? ? "application" : "devise" }
  # And/or Sessions, Confirmations, Unlocks, Passwords
end
Clone this wiki locally
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.