module ActionPolicy::Policy::Cache

Provides long-lived cache through ActionPolicy.cache_store.

NOTE: if cache_store is nil then we silently skip all the caching.

Public Class Methods

included(base) click to toggle source
# File lib/action_policy/policy/cache.rb, line 21
def included(base)
  base.extend ClassMethods
end

Public Instance Methods

apply(rule) click to toggle source
Calls superclass method
# File lib/action_policy/policy/cache.rb, line 64
def apply(rule)
  return super if ActionPolicy.cache_store.nil? ||
    !self.class.cached_rules.key?(rule)

  apply_with_cache(rule) { super }
end
apply_with_cache(rule) { || ... } click to toggle source
# File lib/action_policy/policy/cache.rb, line 48
def apply_with_cache(rule)
  options = self.class.cached_rules.fetch(rule)
  key = rule_cache_key(rule)

  ActionPolicy.cache_store.then do |store|
    @result = store.read(key)
    unless result.nil?
      result.cached!
      next result.value
    end
    yield
    store.write(key, result, options)
    result.value
  end
end
cache(*parts, **options) { || ... } click to toggle source
# File lib/action_policy/policy/cache.rb, line 71
def cache(*parts, **options)
  key = cache_key(*parts)
  ActionPolicy.cache_store.then do |store|
    res = store.read(key)
    next res unless res.nil?
    res = yield
    store.write(key, res, options)
    res
  end
end
cache_key(*parts) click to toggle source
# File lib/action_policy/policy/cache.rb, line 28
def cache_key(*parts)
  [
    cache_namespace,
    *parts
  ].map { _1._policy_cache_key }.join("/")
end
cache_namespace() click to toggle source
# File lib/action_policy/policy/cache.rb, line 26
  def cache_namespace() = ActionPolicy::CACHE_NAMESPACE

  def cache_key(*parts)
    [
      cache_namespace,
      *parts
    ].map { _1._policy_cache_key }.join("/")
  end

  def rule_cache_key(rule)
    cache_key(
      context_cache_key,
      record,
      self.class,
      rule
    )
  end

  def context_cache_key
    authorization_context.map { _2._policy_cache_key.to_s }.join("/")
  end

  def apply_with_cache(rule)
    options = self.class.cached_rules.fetch(rule)
    key = rule_cache_key(rule)

    ActionPolicy.cache_store.then do |store|
      @result = store.read(key)
      unless result.nil?
        result.cached!
        next result.value
      end
      yield
      store.write(key, result, options)
      result.value
    end
  end

  def apply(rule)
    return super if ActionPolicy.cache_store.nil? ||
      !self.class.cached_rules.key?(rule)

    apply_with_cache(rule) { super }
  end

  def cache(*parts, **options)
    key = cache_key(*parts)
    ActionPolicy.cache_store.then do |store|
      res = store.read(key)
      next res unless res.nil?
      res = yield
      store.write(key, res, options)
      res
    end
  end

  module ClassMethods # :nodoc:
    def cache(*rules, **options)
      rules.each do |rule|
        cached_rules[rule] = options
      end
    end

    def cached_rules
      return @cached_rules if instance_variable_defined?(:@cached_rules)

      @cached_rules = if superclass.respond_to?(:cached_rules)
        superclass.cached_rules.dup
      else
        {}
      end
    end
  end
end
context_cache_key() click to toggle source
# File lib/action_policy/policy/cache.rb, line 44
def context_cache_key
  authorization_context.map { _2._policy_cache_key.to_s }.join("/")
end
rule_cache_key(rule) click to toggle source
# File lib/action_policy/policy/cache.rb, line 35
def rule_cache_key(rule)
  cache_key(
    context_cache_key,
    record,
    self.class,
    rule
  )
end