[英]Pundit policy_scope error: undefined method `admin?' for nil:NilClass
Running into something I don't understand with Pundit, 碰到Pundit不了解的事情,
Using Rails 4.2.5.1, Pundit 1.1.0 with Devise for authentication. 使用带有Devise的Rails 4.2.5.1和Pundit 1.1.0进行身份验证。
I'm trying to use a policy scope for the BlogController#Index action. 我正在尝试对BlogController#Index操作使用策略范围。
Getting an error: 出现错误:
undefined method `admin?' 未定义的方法“管理员?” for nil:NilClass 对于nil:NilClass
Live shell reveals: 活壳显示:
>> user
=> nil
# ApplicationController
class ApplicationController < ActionController::Base
include Pundit
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
private
def user_not_authorized
flash[:error] = "You are not authorized to perform this action."
redirect_to(request.referrer || root_path)
end
end
# BlogController
# == Schema Information
#
# Table name: blogs
#
# id :integer not null, primary key
# title :string default(""), not null
# body :text default(""), not null
# published :boolean default("false"), not null
# created_at :datetime not null
# updated_at :datetime not null
#
class BlogsController < ApplicationController
before_action :set_blog, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
after_action :verify_authorized, except: [:index, :show]
after_action :verify_policy_scoped, only: [:index]
def index
@blogs = policy_scope(Blog)
authorize @blog
end
def show
end
def new
@blog = Blog.new
authorize @blog
end
def edit
authorize @blog
end
def create
@blog = Blog.new(blog_params)
@blog.user = current_user if user_signed_in?
authorize @blog
if @blog.save
redirect_to @blog, notice: "Blog post created."
else
render :new
end
end
def update
authorize @blog
if @blog.update(blog_params)
redirect_to @blog, notice: "Blog updated."
else
render :edit
end
end
def destroy
authorize @blog
@blog.destroy
redirect_to blogs_url, notice: "Blog post deleted."
end
private
def set_blog
@blog = Blog.friendly.find(params[:id])
end
def blog_params
params.require(:blog).permit(*policy(@blog|| Blog).permitted_attributes)
end
end
# Application Policy
class ApplicationPolicy
attr_reader :user, :record
def initialize(user, record)
@user = user
@record = record
end
def index?
false
end
def show?
scope.where(:id => record.id).exists?
end
def create?
false
end
def new?
create?
end
def update?
false
end
def edit?
update?
end
def destroy?
false
end
def scope
Pundit.policy_scope!(user, record.class)
end
class Scope
attr_reader :user, :scope
def initialize(user, scope)
@user = user
@scope = scope
end
def resolve
scope
end
end
end
# Blog Policy
class BlogPolicy < ApplicationPolicy
class Scope < Scope
def resolve
if user.admin?
scope.all
else
scope.where(published: true)
end
end
end
def new?
user.admin?
end
def index?
true
end
def update?
user.admin?
end
def create?
user.admin?
end
def destroy?
user.admin?
end
def permitted_attributes
if user.admin?
[:title, :body]
end
end
end
In the Pundit BlogPolicy scope I've created: 在Pundit BlogPolicy范围中,我创建了:
class Scope < Scope
def resolve
if user.admin?
scope.order('id DESC')
else
scope.where('published: true')
end
end
end
If I log in as an
admin user
it works fine. 如果我以admin user
身份登录,则可以正常运行。
I'm able to view all blog posts. 我可以查看所有博客文章。
If I log in as a standard
user
it works. 如果我以标准user
身份登录,则可以正常工作。
Standard user sees blog posts that are marked published. 标准用户将看到标记为已发布的博客文章。
If I'm not logged in where
user is nil
I get an error: 如果我未在user is nil
地方登录,user is nil
收到错误消息:
NoMethodError at /blog
undefined method `admin?' for nil:NilClass
I can add another clause elsif user.nil?
我可以添加另一个子句elsif user.nil?
before user.admin?
在user.admin?
之前user.admin?
or a case when
statement but I thought if the user is not an admin it should just display what is in the else block? 还是一个case when
语句,但我认为如果用户不是管理员,它应该只显示else块中的内容?
# This seems wrong?
class Scope < Scope
def resolve
if user.nil?
scope.where('published: true')
elsif user.admin?
scope.all
else
scope.where('published: true')
end
end
end
Any pointers much appreciated 任何指针表示赞赏
You can use try: 您可以使用try:
if user.try(:admin?)
# do something
end
http://api.rubyonrails.org/v4.2.5/classes/Object.html#method-i-try http://api.rubyonrails.org/v4.2.5/classes/Object.html#method-i-try
This happens because there is no user when you are not logged in. (Probably to user
variable nil
value is assigned somewhere, so you are trying to call admin?
method on nil
object) 发生这种情况的原因是,当您未登录时没有用户。(可能是user
变量nil
值分配在某个地方,因此您试图在nil
对象上调用admin?
方法)
If you use ruby 2.3.0 or newer you had better use safe navigation 如果您使用ruby 2.3.0或更高版本,则最好使用安全导航
if user&.admin?
scope.order('id DESC')
else
scope.where('published: true')
end
If you user other ruby version 如果您使用其他红宝石版本
if user.try(:admin?)
scope.order(id: :desc)
else
scope.where(published: true)
end
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.