设计中签名作用的不同布局

我正在尝试使用一个不同的/自定义布局名为“设计”的登录操作。我在 design wiki 中找到了 这个页面,第二个例子甚至说你可以按照每个动作来做(在这个例子中是 sign_in动作) ,但是它没有显示这样做的例子。IRC 上有人告诉我,我可以试试这个:

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

但它似乎不工作,因为它仍然加载默认的应用程序布局。如果你能帮忙,我会很感激的。

43130 次浏览

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.

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"}

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.

I just created app/views/layouts/devise/sessions.html.erb and put my layout in there.

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

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

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