Class: Reeve::Authorization::Adapters::Pundit
- Inherits:
-
Object
- Object
- Reeve::Authorization::Adapters::Pundit
- Defined in:
- lib/reeve/authorization/adapters/pundit.rb
Overview
Pundit policies, bridged rather than depended on. Pundit itself is never required by this gem (Constitution IV); this file only speaks its conventions, and reports that it supports nothing when Pundit is absent.
class InvoicePolicy
def index? = ...
class Scope < ApplicationPolicy::Scope
def resolve = scope.where(owner: user)
end
end
Class Method Summary collapse
- .missing_methods(policy) ⇒ Object
- .policy_ancestry(policy) ⇒ Object
- .pundit_loaded? ⇒ Boolean
-
.scope_defined?(policy) ⇒ Boolean
Pundit policies ordinarily inherit their Scope from a base policy (
class LeadPolicy < LeadBasePolicy), so asking only the policy's own namespace rejected the common case. - .supports?(policy) ⇒ Boolean
Instance Method Summary collapse
- #authorize(principal:, policy:, action:, record: nil) ⇒ Object
-
#policy_for(record_class) ⇒ Object
Pundit's own convention, which is what makes per-type scoping of a mixed result possible at all: Invoice => InvoicePolicy.
- #scope(principal:, policy:, relation:) ⇒ Object
- #scope_rule(policy) ⇒ Object
Class Method Details
.missing_methods(policy) ⇒ Object
44 45 46 47 48 49 |
# File 'lib/reeve/authorization/adapters/pundit.rb', line 44 def self.missing_methods(policy) return [] if supports?(policy) return [:Scope] if policy.is_a?(Class) && !scope_defined?(policy) %i[query_method Scope] end |
.policy_ancestry(policy) ⇒ Object
40 41 42 |
# File 'lib/reeve/authorization/adapters/pundit.rb', line 40 def self.policy_ancestry(policy) policy.ancestors.take_while { |ancestor| ancestor != Object } end |
.pundit_loaded? ⇒ Boolean
17 18 19 |
# File 'lib/reeve/authorization/adapters/pundit.rb', line 17 def self.pundit_loaded? defined?(::Pundit) ? true : false end |
.scope_defined?(policy) ⇒ Boolean
Pundit policies ordinarily inherit their Scope from a base policy
(class LeadPolicy < LeadBasePolicy), so asking only the policy's own namespace
rejected the common case. This walks the ancestry instead, stopping before
Object — which is the whole reason the check was narrow to begin with: a
top-level Scope constant must never make an unrelated class look
Pundit-shaped. policy::Scope resolves along the same ancestry, so what
supports? accepts is exactly what scope can later reach.
36 37 38 |
# File 'lib/reeve/authorization/adapters/pundit.rb', line 36 def self.scope_defined?(policy) policy_ancestry(policy).any? { |ancestor| ancestor.const_defined?(:Scope, false) } end |
.supports?(policy) ⇒ Boolean
21 22 23 24 25 26 27 |
# File 'lib/reeve/authorization/adapters/pundit.rb', line 21 def self.supports?(policy) return false unless pundit_loaded? return false unless policy.is_a?(Class) scope_defined?(policy) && policy.public_instance_methods.any? { |method| method.to_s.end_with?("?") } end |
Instance Method Details
#authorize(principal:, policy:, action:, record: nil) ⇒ Object
51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/reeve/authorization/adapters/pundit.rb', line 51 def (principal:, policy:, action:, record: nil) query = "#{action}?" rule = "#{policy.name}##{query}" subject = record || inferred_subject(policy) if policy.new(principal, subject).public_send(query) Decision.allow(rule: rule) else Decision.deny(rule: rule) end end |
#policy_for(record_class) ⇒ Object
Pundit's own convention, which is what makes per-type scoping of a mixed result possible at all: Invoice => InvoicePolicy.
77 78 79 80 81 82 |
# File 'lib/reeve/authorization/adapters/pundit.rb', line 77 def policy_for(record_class) name = "#{record_class.name}Policy" Object.const_defined?(name) ? Object.const_get(name) : nil rescue NameError nil end |
#scope(principal:, policy:, relation:) ⇒ Object
64 65 66 67 68 69 |
# File 'lib/reeve/authorization/adapters/pundit.rb', line 64 def scope(principal:, policy:, relation:) scoped = policy::Scope.new(principal, relation).resolve return scoped unless scoped.nil? raise Error, "#{scope_rule(policy)} returned nil; a scope must return a relation" end |
#scope_rule(policy) ⇒ Object
71 72 73 |
# File 'lib/reeve/authorization/adapters/pundit.rb', line 71 def scope_rule(policy) "#{policy.name}::Scope" end |