遇到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