I\'m trying to use a different/custom layout named \"devise\" for the sign_in action. I found this page in the devise wiki, and the second example even says you can do it pe
Surprised to not see this answer anywhere, but you can also do this:
In routes.rb, change your devise config to look something like this:
devise_for :users, controllers: {
sessions: 'sessions'
}
Then in app/controllers/sessions_controller.rb
class SessionsController < Devise::SessionsController
layout 'devise', only: [:new]
end
This is especially useful if you need to do additional logic overrides in any of the Devise controllers.
The by far simplest solution is to just create a layout called devise.html.haml in your app/views/layouts folder. and the Rails magic takes care of the rest.
app/views/layouts/devise.html.haml
Another way to apply custom layout for an action is as following.
According to How To: Create custom layouts "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."
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
Usually a layout distinction is made between pages behind login and pages which do not require authentication, so the above approach works most of the time. But I also experimented with using action_name
helper to set a layout for a particular action and it worked like charm:
config.to_prepare do
Devise::SessionsController.layout proc{ |controller| action_name == 'new' ? "devise" : "application" }
end
I think this is the better and built in way to change the layout based on devise controller/action instead of creating a helper in ApplicationController.
This is how I did it. I wanted a different layout if the user had to sign in, but a different layout if the user had to edit his/her profile.
I am using Rails 4.1.1
In the application controller, add this :
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_action :configure_permitted_parameters, if: :devise_controller?
layout :layout_by_resource
# Define the permitted parameters for Devise.
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:firstname, :lastname, :email, :password, :password_confirmation)}
devise_parameter_sanitizer.for(:account_update) { |u| u.permit(:avatar, :firstname, :lastname, :email, :password, :password_confirmation, :current_password) }
end
def layout_by_resource
if devise_controller? and user_signed_in?
'dashboard'
else
'application'
end
end
end
I just created app/views/layouts/devise/sessions.html.erb and put my layout in there.
I figured it out, but I'll keep this question here in case other people are curious.
It was a stupid mistake. The fact is sign_in
is the path, not the action. Looking at the relevant source, I can see that the required action is new
, i.e., creating a new Devise Session. Changing my above code's conditional to:
if devise_controller? && resource_name == :user && action_name == 'new'
Works beautifully.
Hope that helps someone out there.