module DeclarativePolicy
DeclarativePolicy: A DSL based authorization framework
Default policy definition for nil values
Constants
- CLASS_CACHE_IVAR
- CLASS_CACHE_MUTEX
- VERSION
Public Class Methods
class_for(subject)
click to toggle source
# File lib/declarative_policy.rb, line 40 def class_for(subject) return configuration.nil_policy if subject.nil? return configuration.named_policy(subject) if subject.is_a?(Symbol) subject = find_delegate(subject) policy_class = class_for_class(subject.class) raise "no policy for #{subject.class.name}" if policy_class.nil? policy_class end
configure(&block)
click to toggle source
# File lib/declarative_policy.rb, line 52 def configure(&block) configuration.instance_eval(&block) nil end
configure!(&block)
click to toggle source
Reset configuration
# File lib/declarative_policy.rb, line 59 def configure!(&block) @configuration = DeclarativePolicy::Configuration.new configure(&block) if block end
policy?(subject)
click to toggle source
# File lib/declarative_policy.rb, line 64 def policy?(subject) !class_for_class(subject.class).nil? end
Also aliased as: has_policy?
policy_for(user, subject, opts = {})
click to toggle source
# File lib/declarative_policy.rb, line 27 def policy_for(user, subject, opts = {}) cache = opts[:cache] || {} key = Cache.policy_key(user, subject) cache[key] ||= # to avoid deadlocks in multi-threaded environment when # autoloading is enabled, we allow concurrent loads, # https://gitlab.com/gitlab-org/gitlab-foss/issues/48263 ActiveSupport::Dependencies.interlock.permit_concurrent_loads do class_for(subject).new(user, subject, opts) end end
Private Class Methods
class_for_class(subject_class)
click to toggle source
This method is heavily cached because there are a lot of anonymous modules in play in a typical rails app, and name performs quite slowly for anonymous classes and modules.
See bugs.ruby-lang.org/issues/11119
if the above bug is resolved, this caching could likely be removed.
# File lib/declarative_policy.rb, line 82 def class_for_class(subject_class) unless subject_class.instance_variable_defined?(CLASS_CACHE_IVAR) CLASS_CACHE_MUTEX.synchronize do # re-check in case of a race break if subject_class.instance_variable_defined?(CLASS_CACHE_IVAR) policy_class = compute_class_for_class(subject_class) subject_class.instance_variable_set(CLASS_CACHE_IVAR, policy_class) end end subject_class.instance_variable_get(CLASS_CACHE_IVAR) end
compute_class_for_class(subject_class)
click to toggle source
# File lib/declarative_policy.rb, line 96 def compute_class_for_class(subject_class) return subject_class.declarative_policy_class.constantize if subject_class.respond_to?(:declarative_policy_class) subject_class.ancestors.each do |klass| name = klass.name klass = policy_class(name) return klass if klass end nil end
configuration()
click to toggle source
# File lib/declarative_policy.rb, line 71 def configuration @configuration ||= DeclarativePolicy::Configuration.new end
find_delegate(subject)
click to toggle source
# File lib/declarative_policy.rb, line 115 def find_delegate(subject) seen = Set.new while subject.respond_to?(:declarative_policy_delegate) raise ArgumentError, 'circular delegations' if seen.include?(subject.object_id) seen << subject.object_id subject = subject.declarative_policy_delegate end subject end
policy_class(name)
click to toggle source
# File lib/declarative_policy.rb, line 109 def policy_class(name) clazz = configuration.policy_class(name) clazz if clazz && clazz < Base end