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