可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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 per-action (in this case, sign_in
action), but it shows no example of doing that. Someone on IRC told me I could try this:
class ApplicationController < ActionController::Base
protect_from_forgery
layout :layout_by_resource
def layout_by_resource
if devise_controller? && resource_name == :user && action_name == 'sign_in'
"devise"
else
"application"
end
end
end
But it does not seem to be working as it's still loading the default application layout. I would appreciate any help.
回答1:
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.
回答2:
I just created app/views/layouts/devise/sessions.html.erb and put my layout in there.
回答3:
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.
回答4:
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
回答5:
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
回答6:
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.
回答7:
Just incase you didn't know, you can also use rake routes
to see the routes in your rails app along with the action/controller they map to.
new_user_registration GET /accounts/sign_up(.:format) {:action=>"new", :controller=>"devise/registrations"}
edit_user_registration GET /accounts/edit(.:format) {:action=>"edit", :controller=>"devise/registrations"}
PUT /accounts(.:format) {:action=>"update", :controller=>"devise/registrations"}
DELETE /accounts(.:format) {:action=>"destroy", :controller=>"devise/registrations"}
回答8:
Here's a one-liner for those who want all devise actions to use a new layout:
class ApplicationController < ActionController::Base
protect_from_forgery
layout Proc.new { |controller| controller.devise_controller? ? 'devise' : 'application' }
end