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.

Returns:

  • (Boolean)


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

Returns:

  • (Boolean)


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