2016-02-19 3 views
1

Запуск во что-то, что я не понимаю с помощью Pundit,Pundit policy_scope error: undefined method `admin? ' для nil: NilClass

Использование Rails 4.2.5.1, Pundit 1.1.0 с настройкой для аутентификации.

Я пытаюсь использовать область политики для действия Index Index BlogController.

  • Если пользователь администратор, отображать все сообщения (проекты, опубликованные)
  • Если пользователь является стандартным, отображение сообщений, отмеченные опубликованы только
  • Если ни один пользователь/пользователь не вошел в систему, сообщений дисплей, отмеченные опубликованы только

Получение ошибки:

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 

я могу добавить еще один пункт elsif user.nil? перед user.admin? или case when заявление, но я подумал, что если пользователь не является администратором он должен просто показать то, что находится в блоке еще?

# 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

Вы можете использовать попробовать:.

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

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

+0

Благодаря Дрю, вы думаете, что лучше, если не использовать .try (?: Админ), что в индекс BlogController # Я использую условие вроде: if user_signed_in? policy_scope (блог) else Blog.where (опубликовано: true)? –

+0

Не обязательно. Перемещение этого элемента в контроллер означало бы, что вам придется вручную проверить, был ли пользователь подписан снова, если вы когда-либо захотите повторно использовать policy_scope в другом месте. – Drew

+0

Спасибо Дрю. Попробуйте! –

1

Это происходит потому, что нет ни одного пользователя, когда вы не вошли в систему (возможно, чтобы user значение переменной nil присваивается где-то, поэтому вы пытаетесь вызвать метод admin? на nil)

Если вы используете рубин 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