NoMethodError 未定义方法“管理员?”对于 nil:NilClass 专家,设计 Rails

NoMethodError undefined method `admin?' for nil:NilClass Pundit, Devise Rails

我正在尝试将专家与我的活动管理员集成并设计配置。但该应用程序运行异常。它将 model/record 作为 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

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

专家policy doc says that it calls the current_user method to retrieve what to send into the first argument of the initialize method inside the Policy class. If you have configured ActiveAdmin to retrieve the current logged in user by using current_admin_user, then you have to override the pundit default method in your ApplicationController class like so: 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会有匹配的PostPolicyclass,并实例化这个class,将当前用户和给定的记录。然后它从操作名称推断出它应该在这个策略实例上调用 update?。在这种情况下,你可以想象 authorize 会做这样的事情:

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

有了所有这些,在您的情况下,如果您希望在查看所有用户列表之前对用户进行授权,您可以像已经完成的那样定义 AdminUserPolicy。然后在你的 AdminUserController

index 动作中
controller do
  def index
    @users = AdminUser.all
    authorize @users // NOT `authorize current_admin_user`
    super
  end
end

如果您要检查的权限名称与操作名称不匹配,您可以将第二个参数传递给 authorize。例如:

def publish
  @post = Post.find(params[:id])
  authorize @post, :update?
  @post.publish!
  redirect_to @post
end