简体   繁体   English

Pundit policy_scope错误:未定义的方法'admin?' 对于nil:NilClass

[英]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操作使用策略范围。

  • If user is admin, display all posts (drafts, published) 如果用户是管理员,则显示所有帖子(草稿,已发布)
  • If user is standard, display posts marked published only 如果用户是标准用户,则显示标记为仅发布的帖子
  • If no user / user not logged in, display posts marked published only 如果没有用户/用户未登录,则显示标记为仅发布的帖子

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 任何指针表示赞赏

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM