NoMethodError未定义方法`admin?'为零:NilClass Pundit,Devise Rails

时间:2017-11-06 04:01:40

标签: devise ruby-on-rails-5 activeadmin pundit

我正在尝试将pundit与我的主动管理员集成并设计配置。但该应用程序很奇怪。它将模型/记录作为current_user。

我的政策文件:

class AdminUserPolicy
  attr_reader :current_user, :model

  def initialize(current_user, model)
    Rails.logger.info '--------------- initialize called-------------------'
    Rails.logger.info current_user
    Rails.logger.info model
    @current_user = current_user
    @record = model
  end

  def index?
    @current_user.admin?
  end
end

控制器:

controller do
    include Pundit
    protect_from_forgery
    rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
    before_action :authenticate_admin_user!

    def index
        authorize current_admin_user
        super
    end

    private

        def user_not_authorized
           flash[:alert]="Access denied"
           redirect_to (request.referrer || admin_root_path)
        end
end

日志如下:

--------------- initialize called----------------------------------------

#<AdminUser:0x007f27733f8a80>
Completed 500 Internal Server Error in 364ms (ActiveRecord: 312.8ms)



NoMethodError (undefined method `admin?' for nil:NilClass):

app/policies/admin_user_policy.rb:13:in `index?'
app/admin/dashboard.rb:19:in `index'
  Rendering /usr/local/rvm/gems/ruby-2.3.4/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout
  Rendering /usr/local/rvm/gems/ruby-2.3.4/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/_source.html.erb
  Rendered /usr/local/rvm/gems/ruby-2.3.4/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/_source.html.erb (4.8ms)
  Rendering /usr/local/rvm/gems/ruby-2.3.4/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb
  Rendered /usr/local/rvm/gems/ruby-2.3.4/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (2.5ms)
  Rendering /usr/local/rvm/gems/ruby-2.3.4/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb
  Rendered /usr/local/rvm/gems/ruby-2.3.4/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb (1.1ms)
  Rendered /usr/local/rvm/gems/ruby-2.3.4/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout (39.5ms)

根据日志current_user=nilmodel=#<AdminUser:0x007f27733f8a80>

,奇怪的部分是

我将current_user与我的策略文件模型交换为

def index?
  @record.admin?
end

它有效! 我不明白这种奇怪的行为。

1 个答案:

答案 0 :(得分:1)

Pundit policy doc表示它调用current_user方法来检索要发送到Policy类中initialize方法的第一个参数的内容。如果您已使用current_admin_user配置ActiveAdmin以检索当前登录用户,则必须覆盖ApplicationController类中的权威默认方法,如下所示:Ref

class ApplicationController < ActionController::Base
  // ...
  def pundit_user
    current_admin_user // or whatever based on ActiveAdmin initializer config
  end
end

为了使定义的策略有效,您必须使用相应策略模型的实例在控制器操作中调用authorize。因此,如果您有PostPolicy并且想要授权update操作,则必须执行以下操作:

controller do
  def update
    @post = Post.find(params[:id])
    authorize @post // the current user will be automatically sent to the PostPolicy
    super
  end
end

authorize方法自动推断Post将具有匹配的PostPolicy类,并实例化此类,交付当前用户和给定记录。然后从动作名称推断出它应该在此策略实例上调用update?。在这种情况下,你可以想象authorize会做这样的事情:

unless PostPolicy.new(current_user, @post).update?
  raise Pundit::NotAuthorizedError, "not allowed to update? this #{@post.inspect}"
end

拥有所有这些,在您的情况下,如果您希望在查看所有用户列表之前授权用户,您可以像已经完成的那样定义AdminUserPolicy。然后在index的{​​{1}}操作中,

AdminUserController

如果要检查的权限名称与操作名称不匹配,则可以将第二个参数传递给controller do def index @users = AdminUser.all authorize @users // NOT `authorize current_admin_user` super end end 。例如:

authorize