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
- 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)`.
- If everything should be visible to this policy's users, return `scope.all` (ActiveRecord) or just `scope` (PORO/array).
- If several scopes share the same rule, implement resolve once in a shared base class and inherit from that instead of ApplicationPolicy::Scope.
- 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
- Generate every policy with `rails g pundit:policy Model` so the Scope skeleton (including resolve) is present from the start.
- Write a shared policy spec example that calls `.resolve` on each policy's Scope, so an unimplemented resolve fails in tests before it reaches a controller.
- If most scopes share one rule, implement #resolve in a common base class rather than relying on the ApplicationPolicy placeholder.
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
- Invalid #<#{policy_scope_class}> constructor is called
- unable to find scope `#{find(object)}::Scope` for `#{object.
- Invalid #<#{klass}> constructor is called
- unable to find policy `#{find(object)}` for `#{object.inspec
- No permissions in example metadata, did you forget to wrap w
AI-assisted analysis of varvet/pundit@06318683c9 (2026-08-21).
Data as JSON: /api/errors/7a39f9c3ac575a0b.
Report an issue: GitHub.