我在以前只有一個Devise模型的應用程序中有Devise的一些基本經驗。然而,我從頭開始重寫它以擴展功能,在第二次迭代中,我認爲最好有兩個單獨的用戶模型(patient_user和staff_user)。設置爲多個模型設計after_sign_in_path_for
我知道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應該在應用程序控制器中定義,而不是在Sessions控制器中定義。
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'
我已經嘗試了很多的谷歌搜索的,看着其他各種設計和循環依賴問題,但一直沒能找到周圍工作,我想我不夠好,在設計知道我在做什麼。
我試圖在做patient_user和staff_user分離after_sign_in_path_for在應用控制器調用的一件事
#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)
所以我創建了一個新的控制器文件:
#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: "[email protected]", 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和Vapire他們的幫助!
你可以使用一個調試器,並檢查你的after_sign_in_path_for方法獲得什麼資源值? – Mandeep
我該怎麼做?對Rails來說,我還是有點新鮮,並且只是圍繞我的應用程序構建一個完整的Cucumber/RSpec測試套件。我認爲找出資源中的資源是個好主意,但不知道如何去做,我想可能是使用rails控制檯的東西,但是我也沒有太多的經驗。 – user2792268
檢查http://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debugger-gem – Mandeep