varvet--pundit/lib/pundit/policy_finder.rb

108 lines
2.9 KiB
Ruby

module Pundit
# Finds policy and scope classes for given object.
# @api public
# @example
# user = User.find(params[:id])
# finder = PolicyFinder.new(user)
# finder.policy #=> UserPolicy
# finder.scope #=> UserPolicy::Scope
#
class PolicyFinder
attr_reader :object
# @param object [any] the object to find policy and scope classes for
#
def initialize(object)
@object = object
end
# @return [nil, Scope{#resolve}] scope class which can resolve to a scope
# @see https://github.com/elabs/pundit#scopes
# @example
# scope = finder.scope #=> UserPolicy::Scope
# scope.resolve #=> <#ActiveRecord::Relation ...>
#
def scope
policy::Scope if policy
rescue NameError
nil
end
# @return [nil, Class] policy class with query methods
# @see https://github.com/elabs/pundit#policies
# @example
# policy = finder.policy #=> UserPolicy
# policy.show? #=> true
# policy.update? #=> false
#
def policy
klass = find
klass = klass.constantize if klass.is_a?(String)
klass
rescue NameError
nil
end
# @return [Scope{#resolve}] scope class which can resolve to a scope
# @raise [NotDefinedError] if scope could not be determined
#
def scope!
raise NotDefinedError, "unable to find policy scope of nil" if object.nil?
scope or raise NotDefinedError, "unable to find scope `#{find}::Scope` for `#{object.inspect}`"
end
# @return [Class] policy class with query methods
# @raise [NotDefinedError] if policy could not be determined
#
def policy!
raise NotDefinedError, "unable to find policy of nil" if object.nil?
policy or raise NotDefinedError, "unable to find policy `#{find}` for `#{object.inspect}`"
end
# @return [String] the name of the key this object would have in a params hash
#
def param_key
if object.respond_to?(:model_name)
object.model_name.param_key.to_s
elsif object.is_a?(Class)
object.to_s.demodulize.underscore
else
object.class.to_s.demodulize.underscore
end
end
private
def find
if object.nil?
nil
elsif object.respond_to?(:policy_class)
object.policy_class
elsif object.class.respond_to?(:policy_class)
object.class.policy_class
else
klass = if object.is_a?(Array)
object.map { |x| find_class_name(x) }.join("::")
else
find_class_name(object)
end
"#{klass}#{SUFFIX}"
end
end
def find_class_name(subject)
if subject.respond_to?(:model_name)
subject.model_name
elsif subject.class.respond_to?(:model_name)
subject.class.model_name
elsif subject.is_a?(Class)
subject
elsif subject.is_a?(Symbol)
subject.to_s.camelize
else
subject.class
end
end
end
end