Search code examples
ruby-on-railsruby-on-rails-4pundit

rails4 + Pundit model instance not defined in policy


I defines a Pundit policy "CompanyPolicy" as stated in the documentation , the scopez gives the expected results ( on :index ) but I get an exception trying to use the company model instance :

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

here is the 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

and I check it from the Company controller

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

why (company[:short_name] is wrong ?

If I look into the Pundit doc , the example with the PostPolicy , scope and post.published is similar ...

        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

Solution

  • Take a look into 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.