-
Notifications
You must be signed in to change notification settings - Fork 5.5k
How To: Create custom layouts
If you would like to use a custom layout or layouts for Devise views, you have the following options:
- Use
layout
in individual Controllers - Use
layout
anddevise_controller?
in ApplicationController - Configure layouts for individual controllers in
config/application.rb
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 Users::RegistrationsController < Devise::RegistrationsController
layout "devise", only: [:edit]
end
# then add this to your routes:
devise_for :users, controllers: { registrations: 'users/registrations' }
# With custom Devise parent controller
# config/initializers/devise.rb
config.parent_controller = 'MyBaseDeviseController'
# Controller
class MyBaseDeviseController < ApplicationController
layout "devise"
end
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
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
# Optional: Ensure that Routes and therefore Controller mixins like authenticate_user! are defined before autoloading Controllers
Rails.application.reload_routes!
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
Another approach to assigning the Devise Mailer layout is to change the config.parent_mailer
from ActionMailer::Base
to a mailer defined within the application, for example: ApplicationMailer
.