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



我正在尝试将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

它起作用了!我不理解这种奇怪的行为。

Pundit策略文档表示,它调用current_user方法来检索要发送到policy类内initialize方法的第一个参数中的内容。如果您已将ActiveAdmin配置为使用current_admin_user检索当前登录的用户,那么您必须覆盖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。然后在AdminUserControllerindex动作中,

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

相关内容

最新更新