Rails Devise:在authenticate_group中调用super!在Controller

时间:2018-02-15 23:18:36

标签: ruby-on-rails devise

Devise有一个名为devise_group的便捷功能(链接到documentation),可以创建一个包含多个设计模型的组。

文档真的是自我解释的。如果您有两个名为的设计模型,例如AdminUser,则可以像devise_group那样使用:

class ApplicationController < ActionController::Base
  devise_group :blogger, contains: [:user, :admin]
end

这将为authenticate_user!authenticate_admin!提供方法authenticate_blogger!,除非用户或管理员已登录,否则会重定向。

我们一直在生产中使用它,效果很好。我们可以灵活地使用authenticate_admin!将某些控制器/操作限制为管理员,并在我们同时访问它时使用authenticate_blogger!

由于我们有一些复杂的业务逻辑,我们不得不在ApplicationController中覆盖authenticate_user!,遵循这个很好的StackOverflow回答here

基本上它建议覆盖ApplicationController#authenticate_user!当我们希望流程遵循Devise时,调用super

当我们尝试使用`authenticate_blogger!做同样的解决方案时,出现了问题。如果我们这样做:

class ApplicationController < ActionController::Base
  devise_group :blogger, contains: [:user, :admin]

  def authenticate_blogger!
    super
  end

end

// Another controller

class DashboardController < ApplicationController

  before_action :authenticate_blogger!

end

Rails引发了这个错误:

super: no superclass method `authenticate_blogger!' for #<DashboardController:0x00007fd453ca5d80> Did you mean? authenticate_user!

任何想法为什么在ApplicationController中覆盖authenticate_user!的覆盖范围内的super都可以正常工作,但同样的设计组不会发生同样的情况吗?

编辑1:找出原因,但可以使用一些帮助改进解决方案

查看devise source codedevise_group使用Ruby class_eval在其调用的类的上下文中定义实例方法,如authenticate_blogger!

因此,当我们在devise_group中使用ApplicationController时,就像我们将authenticate_blogger!定义为ApplicationController中的实例方法一样。

这就是为什么当我们在ApplicationController中手动定义方法authenticate_blogger!并调用super时它会引发异常,因为我们实际上在同一个类(ApplicationController)中覆盖了相同的实例方法,在祖先链中找不到任何东西。

另一方面,

authenticate_user!位于Devise::Controllers::Helpers的祖先链中(我可以看到它调用ApplicationController.ancestors`。

我们所做的hacky-proof-of-concept-fix是创建一个TempController,在其中定义devise_group,并使ApplicationController继承它:

class TempController < ActionController::Base

  devise_group :advertiser, contains: [:user, :broker]

end

// In application_controller.rb

class ApplicationController < TempController

  def authenticate_blogger!
    super // this now works since it goes up in the ancestor chain and finds authenticate_blogger in TempController
  end

end

即使很难对我的调查感到高兴...有关修复此问题的任何建议,而不必让ApplicationController不继承ActionController :: Base,就像它在Rails中的默认值一样?

0 个答案:

没有答案