Module: ActionPolicy::Policy::Core

Includes:
Behaviours::PolicyFor
Included in:
Base
Defined in:
lib/action_policy/policy/core.rb

Overview

Core policy API

Defined Under Namespace

Modules: ClassMethods

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Behaviours::PolicyFor

#authorization_context, #authorization_namespace, #authorization_strict_namespace, #build_authorization_context, #default_authorization_policy_class, #implicit_authorization_target, #implicit_authorization_target!, #policy_for, #policy_for_cache_key

Instance Attribute Details

#recordObject (readonly)

Returns the value of attribute record.



75
76
77
# File 'lib/action_policy/policy/core.rb', line 75

def record
  @record
end

Class Method Details

.included(base) ⇒ Object



43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/action_policy/policy/core.rb', line 43

def included(base)
  base.extend ClassMethods

  # Generate a new class for each _policy chain_
  # in order to extend it independently
  base.module_eval do
    @result_class = Class.new(ExecutionResult)

    # we need to make this class _named_,
    # 'cause anonymous classes couldn't be marshalled
    base.const_set(:APR, @result_class)
  end
end

Instance Method Details

#__apply__(rule) ⇒ Object

This method performs the rule call. Override or extend it to provide custom functionality (such as caching, pre checks, etc.)



118
# File 'lib/action_policy/policy/core.rb', line 118

def __apply__(rule) = public_send(rule)

#allow!Object



110
111
112
113
# File 'lib/action_policy/policy/core.rb', line 110

def allow!
  result&.load true
  throw :policy_fulfilled
end

#allowed_to?(rule, record = :__undef__, **options) ⇒ Boolean

Returns a result of applying the specified rule to the specified record. Under the hood a policy class for record is resolved (unless it’s explicitly set through with option).

If record is nil then we uses the current policy.



138
139
140
141
142
143
144
145
146
# File 'lib/action_policy/policy/core.rb', line 138

def allowed_to?(rule, record = :__undef__, **options)
  if (record == :__undef__ || record == self.record) && options.empty?
    __apply__(resolve_rule(rule))
  else
    policy_for(record: record, **options).then do |policy|
      policy.apply(policy.resolve_rule(rule))
    end
  end
end

#apply(rule) ⇒ Object

Returns a result of applying the specified rule (true of false). Unlike simply calling a predicate rule (policy.manage?), apply also calls pre-checks.



85
86
87
88
89
90
91
92
# File 'lib/action_policy/policy/core.rb', line 85

def apply(rule)
  res = apply_r(rule)

  # DEPRECATED (we still rely on it in tests)
  @result = res

  res.value
end

#apply_r(rule) ⇒ Object

NEXT_RELEASE: This is gonna be #apply in 1.0



95
96
97
98
99
100
101
102
103
# File 'lib/action_policy/policy/core.rb', line 95

def apply_r(rule) # :nodoc:
  with_result(rule) do |result|
    catch :policy_fulfilled do
      result.load __apply__(resolve_rule(rule))
    end

    result
  end
end

#check?(*args, **hargs) ⇒ Boolean

An alias for readability purposes



149
# File 'lib/action_policy/policy/core.rb', line 149

def check?(*args, **hargs) = allowed_to?(*args, **hargs)

#deny!Object



105
106
107
108
# File 'lib/action_policy/policy/core.rb', line 105

def deny!
  result&.load false
  throw :policy_fulfilled
end

#initialize(record = nil) ⇒ Object

NEXT_RELEASE: deprecate record arg, migrate to ‘record: nil`



78
79
80
# File 'lib/action_policy/policy/core.rb', line 78

def initialize(record = nil, *)
  @record = record
end

#inspect_rule(rule) ⇒ Object

Return annotated source code for the rule NOTE: require “method_source” and “prism” gems to be installed. Otherwise returns empty string.



172
# File 'lib/action_policy/policy/core.rb', line 172

def inspect_rule(rule) = PrettyPrint.print_method(self, rule)

#pp(rule) ⇒ Object

Helper for printing the annotated rule source. Useful for debugging: type ‘pp :show?` within the context of the policy to preview the rule.



177
178
179
180
181
182
183
# File 'lib/action_policy/policy/core.rb', line 177

def pp(rule)
  with_result(rule) do
    header = "#{self.class.name}##{rule}"
    source = inspect_rule(rule)
    $stdout.puts "#{header}\n#{source}"
  end
end

#resolve_rule(activity) ⇒ Object

Returns a rule name (policy method name) for activity.

By default, rule name is equal to activity name.

Raises ActionPolicy::UnknownRule when rule is not found in policy.

Raises:



156
157
158
159
160
# File 'lib/action_policy/policy/core.rb', line 156

def resolve_rule(activity)
  raise UnknownRule.new(self, activity) unless
    respond_to?(activity)
  activity
end

#resultObject

Returns the result object for the last rule application within the given execution context (Thread or Fiber)



164
165
166
167
# File 'lib/action_policy/policy/core.rb', line 164

def result
  # FIXME: Remove ivar fallback after 1.0
  Thread.current[:__action_policy_result__]&.last || @result
end

#with_result(rule) ⇒ Object

Prepare a new result object for the next rule application. It’s stored in the thread-local storage to be accessible from within the policy.



122
123
124
125
126
127
128
129
130
131
# File 'lib/action_policy/policy/core.rb', line 122

def with_result(rule) # :nodoc:
  result = self.class.result_class.new(self.class, rule)

  Thread.current[:__action_policy_result__] ||= []
  Thread.current[:__action_policy_result__] << result

  yield result
ensure
  Thread.current[:__action_policy_result__]&.pop
end