ruby-on-rails – Pundit policy_scope错误:未定义的方法`admin?’为零:NilClass

遇到Pundit我不理解的事情,

使用Rails 4.2.5.1,Pundit 1.1.0和Devise进行身份验证.

我正在尝试使用BlogController #Index操作的策略范围.

>如果用户是管理员,则显示所有帖子(草稿,已发布)
>如果用户是标准用户,则显示仅标记为已发布的帖子
>如果没有用户/用户未登录,则显示仅标记为已发布的帖子

得到错误:

undefined method `admin?’ for nil:NilClass

Live shell揭示:

>> 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,: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

在我创建的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.

我可以查看所有博客帖子.

If I log in as a standard user it works.

标准用户会看到标记为已发布的博文.

If I’m not logged in where user is nil I get an error:

NoMethodError at /blog
undefined method `admin?' for nil:NilClass

我可以添加另一个条款elsif user.nil?在user.admin之前?或者声明的情况,但我认为如果用户不是管理员,它应该只显示在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

任何指针都非常赞赏

解决方法

你可以用try:
if user.try(:admin?)
  # do something
end

http://api.rubyonrails.org/v4.2.5/classes/Object.html#method-i-try

相关文章

validates:conclusion,:presence=>true,:inclusion=>{...
一、redis集群搭建redis3.0以前,提供了Sentinel工具来监控各...
分享一下我老师大神的人工智能教程。零基础!通俗易懂!风趣...
上一篇博文 ruby传参之引用类型 里边定义了一个方法名 mo...
一编程与编程语言 什么是编程语言? 能够被计算机所识别的表...
Ruby类和对象Ruby是一种完美的面向对象编程语言。面向对象编...