ruby-on-rails – 使用多个模型设置Devise after_sign_in_path_f
我在以前只有一个Devise模型的应用程序中有一些Devise的基本经验.但是,我从头开始重写它以扩展功能,在第二次迭代中,我认为最好有两个独立的用户模型(patient_user和staff_user).
我知道CanCan和Rolify,并将使用其中一个模型而不是其他模型. 我的问题是设置after_sign_in_path_for并将每个模型重定向到不同的“主屏幕”. 我已将每个模型设置为单独的after_sign_up_path,并且工作得非常好. class RegistrationsController < Devise::RegistrationsController protected # Creating separate after_sign_up_paths for patient_user and staff_user def after_sign_up_path_for(patient_user) flash[:notice] = 'Welcome! You have signed up successfully.' privacy_agreement_path end # Add an after_sign_up path for staff_user def after_sign_up_path_for(staff_user) flash[:notice] = 'Welcome! You have signed up successfully.' dashboard_path end end 显然,after_sign_in_path_for应该在Application Controller中定义,而不是在Sessions Controller中定义. Stack Overflow question clarifying this difference 这是我最好的尝试: 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 def after_sign_in_path_for(resource) case resource when patient_user privacy_agreement_path when staff_user dashboard_path end end end 这给出了错误: undefined local variable or method `patient_user' for #<Devise::SessionsController:0x00000109a40e48> 如果我将案例选择条件大写,那么它似乎识别出变量,但我得到一个完全不同的错误: 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 def after_sign_in_path_for(resource) case resource when Patient_user privacy_agreement_path when Staff_user dashboard_path end end end 这给出了错误 Circular dependency detected while autoloading constant Patient_user (RuntimeError) ./app/controllers/application_controller.rb:11:in `after_sign_in_path_for' 我已经尝试了很多谷歌搜索并查看了其他各种设计和循环依赖问题,但未能找到解决办法,我想我在设计中不够好知道我在做什么. 我尝试的另一件事是在应用程序控制器中调用after_sign_in_path_for的patient_user和staff_user #application_controller.rb def after_sign_in_path_for(patient_user) privacy_agreement_path end def after_sign_in_path_for(staff_user) dashboard_path end 这适用于staff_user,但是转到/ patient_users / sign_in并提供有效的用户名和密码,而是重定向到dashboard_path(而不是privacy_agreement_path). 该问题似乎集中在使用“资源”和旨在将“patient_user”帐户重定向到“privacy_agreement_path”和“staff_user”帐户为“dashboard_path”的条件语句.这适用于RegistrationsController中的after_sign_up_path,但不适用于ApplicationController中的after_sign_in_path. 其他文件 #routes.rb devise_for :patient_users,:controllers => { :registrations => :registrations } devise_for :staff_users,:controllers => { :registrations => :registrations } – #config/initializers/devise.rb # https://stackoverflow.com/questions/8320398/second-devise-model-not-using-generated-views # Workaround for having multiple Devise models,used the second answer config.scoped_views = true 任何帮助将非常感激. 编辑: 我尝试过Vapire的解决方案: 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 def after_sign_in_path_for(resource) # check for the class of the object to determine what type it is case resource.class when PatientUser privacy_agreement_path when StaffUser dashboard_path end end end 但这启动了错误: undefined method `staff_user_url' for #<Devise::SessionsController:0x000001047a0198> (NoMethodError) 有点谷歌搜索我找到了this discussion on Devise github,对于这是某种错误还是只是一个糟糕的实现完全缺乏共识. 我遵循建议的解决方案,即更新routes.rb #routes.rb devise_for :patient_users,:controllers => { :registrations => :registrations } devise_for :staff_users,:controllers => { :registrations => :registrations } resources :patient_users #added as bugfix resources :staff_users #added as bug fix 这给出了一个新的错误: uninitialized constant StaffUsersController (ActionController::RoutingError) 所以我创建了一个新的Controller文件: #controllers/staff_users_controller.rb class StaffUsersController < ApplicationController end 这给了错误 The action 'show' could not be found for StaffUsersController (AbstractController::ActionNotFound) 所以我把它添加到控制器文件中 #controllers/staff_users_controller.rb class StaffUsersController < ApplicationController def show end end 当然,这提示了这个错误: Missing template staff_users/show,application/show with {:locale=>[:en],:formats=>[:html],:handlers=>[:erb,:builder,:raw,:ruby,:jbuilder,:coffee]}. Searched in: 所以我也添加了该文件(只是app / views / staff_users.html.erb中的空白文件) 然后工作,但重定向到错误的页面/ staff_users / 1 所以我再次修改了控制器 #controllers/staff_users_controller.rb class StaffUsersController < ApplicationController def show redirect_to dashboard_path end end 一切正常.这似乎是一个非常复杂的解决方案,但是我必须为PatientUsers做同样的事情,而且我已经选择了许多我不需要的备用资源路径. 编辑2: Mandeep请求的调试器信息. [7,16] in /Users/Me/Code/medapp/app/controllers/application_controller.rb 7 # https://github.com/plataformatec/devise/wiki/How-To%3A-Redirect-to-a-specific-page-on-successful-sign-in-and-sign-out 8 # redirect successfully signed in users to the dashboard 9 def after_sign_in_path_for(resource) 10 debugger 11 # check for the class of the object to determine what type it is => 12 case resource.class 13 when PatientUser 14 privacy_agreement_path 15 when StaffUser 16 dashboard_path (rdb:2) resource.show *** NoMethodError Exception: undefined method `show' for #<PatientUser:0x0000010171c1c0> (rdb:2) @resource = resource #<PatientUser id: 2,email: "patient_user@example.com",encrypted_password: "$2a$10$qY0jBEC8UZHD883ryq69BevPo5oxV.9LPDM8K44gXqcD...",reset_password_token: nil,reset_password_sent_at: nil,remember_created_at: nil,sign_in_count: 16,current_sign_in_at: "2014-07-03 08:46:07",last_sign_in_at: "2014-07-03 08:45:06",current_sign_in_ip: "127.0.0.1",last_sign_in_ip: "127.0.0.1",created_at: "2014-07-03 03:05:01",updated_at: "2014-07-03 08:46:07"> 看起来完全像我预期的那样,应该表明resource.class可以正常工作而没有任何大的变通方法,但显然不是. 解 因此,只需使用If条件而非条件条件修复整个事物,不需要任何其他的东西.我不知道为什么会这样,但这是一个适当的解决方案. #registrations_controller.rb class RegistrationsController < Devise::RegistrationsController protected # BUGFIX # https://stackoverflow.com/questions/19451881/devise-after-sign-in-path-for-works-but-not-the-other-ones # Creating separate after_sign_up_paths for patient_user and staff_user def after_sign_up_path_for(resource) # check for the class of the object to determine what type it is if resource.class == PatientUser privacy_agreement_path elsif resource.class == StaffUser dashboard_path end end end 和 #application_controllers.rb 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 def after_sign_in_path_for(resource) # check for the class of the object to determine what type it is if resource.class == PatientUser privacy_agreement_path elsif resource.class == StaffUser dashboard_path end end end 感谢Mandeep和Vapi??re的帮助! 解决方法
鉴于您的两个用户模型都称为PatientUser和StaffUser,您应该这样做:
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 def after_sign_in_path_for(resource) # check for the class of the object to determine what type it is case resource.class when PatientUser privacy_agreement_path when StaffUser dashboard_path end end end 详细说明你的其他尝试: 在Devise为您登录用户之后,它只需向您的应用程序控制器调用after_sign_in_path(resource).它是否调用Devise本身提供的标准实现或自定义实现对于Devise来说不是问题.如果您自己实现它,它将为您完全做些什么.因此,如果您想对它做出反应,那么您有责任检查作为资源参数的类型. # application_controller.rb # you implement the method once def after_sign_in_path_for(patient_user) privacy_agreement_path end # you implement it twice which means # this overrides the above method,so a call to after_sign_in_path will always # result in calling this method,no matter what type of user it is def after_sign_in_path_for(staff_user) dashboard_path end 仅仅因为您以某种方式命名参数,它就不会提供有关参数类型的信息.这不是OO编程的设计方式. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |