rails4 + Pundit 模型实例未在策略中定义

rails4 + Pundit model instance not defined in policy

我定义了一个 Pundit 策略 "CompanyPolicy" 如文档中所述,scopez 给出了预期的结果(在 :index 上)但是我在尝试使用公司模型实例时遇到异常:

 *** NameError Exception: undefined local variable or method `company' for #<CompanyPolicy:

这里是 CompanyPolicy.rb

  class CompanyPolicy < ApplicationPolicy

      class Scope
        attr_reader :user, :scope

        def initialize(user, scope)
          @user = user
          @scope = scope
        end

        def resolve
          if user.system_admin?
            scope.all
          else
            Company.none
          end
        end
      end

      def new?
        user.system_admin? ? true : false
      end

      def edit?
        user.system_admin? ? true : false
      end

      def show?
        user.system_admin? ? true : false
      end

      def destroy?
        internal_name = Rails.application.secrets.internal_company_short_name
        # do not destroy the internal company record 
        user.system_admin? && (company[:short_name] !=  internal_name ) ? true : false
      end
  end

我从公司控制者那里查看

 def destroy
   authorize @company
   #@company.destroy
   ....
 end

为什么(公司[:short_name]错了?

如果我查看 Pundit 文档,带有 PostPolicy 、范围和 post.published 的示例是相似的...

        class PostPolicy < ApplicationPolicy
          class Scope
            attr_reader :user, :scope

            def initialize(user, scope)
              @user = user
              @scope = scope
            end

            def resolve
              if user.admin?
                scope.all
              else
                scope.where(:published => true)
              end
            end
          end

          def update?
            user.admin? or not post.published?
          end
        end

刚刚发现应该使用@record 而不是公司 (阅读与范围相关的问题:Implementing scopes in Pundit

但我不明白为什么 Pundit 文档没有提到它,并且仍然使用像 'post' 这样的模型实例作为 PostPolicy ... 有人可以启发我们吗?

看看 documentation:

Pundit makes the following assumptions about this class:

  • The class has the same name as some kind of model class, only suffixed with the word "Policy".
  • The first argument is a user. In your controller, Pundit will call the current_user method to retrieve what to send into this argument
  • The second argument is some kind of model object, whose authorization you want to check. This does not need to be an ActiveRecord or even an ActiveModel object, it can be anything really.
  • The class implements some kind of query method, in this case update?. Usually, this will map to the name of a particular
    controller action.

That's it really.

Usually you'll want to inherit from the application policy created by the generator, or set up your own base class to inherit from:

class PostPolicy < ApplicationPolicy
  def update?
    user.admin? or not record.published?
  end
end

In the generated ApplicationPolicy, the model object is called record.