varvet/pundit · error · NoMethodError

You must define #resolve in #{self.class}

Error message

You must define #resolve in #{self.class}

What it means

Pundit's generated ApplicationPolicy ships Scope#resolve as an abstract placeholder that raises NoMethodError. Every policy's nested Scope class must override #resolve to return the records the current user may see (typically an ActiveRecord::Relation or array). Pundit calls resolve after instantiating the scope class with (user, model), so inheriting the placeholder unimplemented makes the raise fire.

Source

Thrown at lib/generators/pundit/install/templates/application_policy.rb.tt:46

    false
  end

  def edit?
    update?
  end

  def destroy?
    false
  end

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

    def resolve
      raise NoMethodError, "You must define #resolve in #{self.class}"
    end

    private

    attr_reader :user, :scope
  end
end

View on GitHub (pinned to 06318683c9)

Solutions

  1. Open the policy class named in the error message and add a nested `class Scope` with a `def resolve` that returns the permitted collection, e.g. `scope.where(user: user)`.
  2. If everything should be visible to this policy's users, return `scope.all` (ActiveRecord) or just `scope` (PORO/array).
  3. If several scopes share the same rule, implement resolve once in a shared base class and inherit from that instead of ApplicationPolicy::Scope.
  4. Confirm the policy class in the message is the one being picked up (naming/namespace conventions) so you are editing the Scope Pundit actually instantiates.

Example fix

# before
class PostPolicy < ApplicationPolicy
  def show?
    true
  end
  # no Scope — controller calls policy_scope(Post) and hits ApplicationPolicy::Scope#resolve
end

# after
class PostPolicy < ApplicationPolicy
  def show?
    true
  end

  class Scope < ApplicationPolicy::Scope
    def resolve
      scope.where(user: user)
    end
  end
end
Defensive patterns

Strategy: validation

Validate before calling

scope_class = Pundit::PolicyFinder.new(record).scope

if scope_class.nil?
  # no scope class at all — policy_scope returns nil; policy_scope! would raise NotDefinedError
elsif scope_class.instance_method(:resolve).owner == ApplicationPolicy::Scope
  # would hit the raising placeholder — do not call policy_scope on this record yet
else
  pundit.policy_scope(record)
end

Type guard

def implements_resolve?(scope_class)
  return false if scope_class.nil?
  scope_class.instance_method(:resolve).owner != ApplicationPolicy::Scope
rescue NameError
  false
end

Try / catch

begin
  pundit.policy_scope(record)
rescue NoMethodError => e
  raise unless e.message.include?("#resolve") # only swallow the unimplemented-placeholder raise
  # scope not implemented for this policy — fall back or re-raise a domain error
  raise MissingPolicyScopeError, "#{record.class}Policy::Scope must define #resolve"
end

Prevention

When it happens

Trigger: Calling any scope-resolution API on a record whose policy Scope does not define #resolve: `pundit.policy_scope(Post)` / `Pundit.policy_scope(user, Post)` in a controller, `pundit.policy_scope!(Post)`, or `Pundit::PolicyFinder.new(Post).scope.resolve` — when `PostPolicy::Scope < ApplicationPolicy::Scope` and no `def resolve ... end` exists in it.

Common situations: Running the pundit:install generator, then hand-writing a policy with only query predicates (show?, edit?) and forgetting the nested Scope; copying a policy file that omits Scope; adding pundit to an existing app and only covering authorize-style checks before the first index action calls policy_scope; inheriting from ApplicationPolicy::Scope assuming the base provides a default resolve.

Related errors


AI-assisted analysis of varvet/pundit@06318683c9 (2026-08-21). Data as JSON: /api/errors/7a39f9c3ac575a0b. Report an issue: GitHub.