2016-02-19 58 views
1

碰到一些我不明白的專家,Pundit policy_scope錯誤:未定義的方法`admin?'對於零:NilClass

使用Rails 4.2.5.1,與設計Pundit 1.1.0進行身份驗證。

我正在嘗試爲BlogController#Index操作使用策略作用域。

  • 如果用戶是管理員,顯示所有職位(草稿,發佈)
  • 如果用戶是標準配置,顯示文章標僅公佈
  • 如果沒有用戶/用戶沒有登錄,顯示的帖子只標明出版

得到一個錯誤:

undefined method `admin?' for nil:NilClass

外殼帶電顯示:

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

在權威人士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 

我可以添加user.admin?前一個條款elsif user.nil?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 

任何指針讚賞

回答

2

您可以使用try:

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

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

+0

感謝德魯,你認爲它的更好,如果不使用。嘗試(?:管理員),在BlogController#索引我使用如下條件:if user_signed_in? policy_scope(Blog)else Blog.where(published:true)? –

+0

不一定。將此移至控制器意味着如果您想要在其他位置重新使用policy_scope,則必須手動檢查用戶是否再次登錄。 – Drew

+0

謝謝德魯。試試看! –

1

這是因爲那裏是當你還沒有登錄沒有用戶(可能是user變量nil值分配在某處,因此您正試圖撥打admin?方法nil對象)

如果你使用ruby 2.3。0或更新你最好使用safe navigation

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

如果用戶其他紅寶石版本

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