Pundit policy_scope错误:未定义的方法`admin?’ 为零:NilClass

遇到Pundit我不理解的事情,

使用Rails 4.2.5.1,Pundit 1.1.0和Devise进行身份validation。

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

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

得到错误:

未定义的方法`admin?’ 为零: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, 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 

在我创建的Pundit BlogPolicy范围中:

  class Scope < Scope def resolve if user.admin? scope.order('id DESC') else scope.where('published: true') end end end 

如果我以admin user身份登录,则可以正常工作。

我可以查看所有博客post。

如果我以标准user身份登录,则可以正常运行。

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

如果我没有登录user is nil我收到错误:

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

我可以添加另一个条款elsif user.nil?user.admin?之前user.admin? 或者声明的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 

任何指针都非常赞赏

你可以用try:

 if user.try(:admin?) # do something end 

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

发生这种情况是因为当您未登录时没有用户。(可能在某处分配了user变量nil值,因此您尝试在nil对象上调用admin?方法)

如果你使用ruby 2.3.0或更新版本,你最好使用安全导航

  if user&.admin? scope.order('id DESC') else scope.where('published: true') end 

如果您使用其他ruby版本

 if user.try(:admin?) scope.order(id: :desc) else scope.where(published: true) end