class ActiveAdmin::PunditAdapter
def authorized?(action, subject = nil)
def authorized?(action, subject = nil) policy = retrieve_policy(subject) action = format_action(action, subject) policy.respond_to?(action) && policy.public_send(action) end
def compat_policy(subject)
This fallback might be removed in future versions of ActiveAdmin, so
detection, so people are probably relying on it.
the only thing that worked in this case before we fixed our buggy namespace
we should try to search it without namespace. This is because that's
I.e.: when class name contains `default_policy_namespace` (eg: ShopAdmin)
This method is needed to fallback to our previous policy searching logic.
def compat_policy(subject) return unless default_policy_namespace target = policy_target(subject) return unless target.class.to_s.include?(default_policy_module) && (policy = policy(target)) policy_name = policy.class.to_s ActiveAdmin.deprecator.warn "You have `pundit_policy_namespace` configured as `#{default_policy_namespace}`, " \ "but ActiveAdmin was unable to find policy #{default_policy_module}::#{policy_name}. " \ "#{policy_name} will be used instead. " \ "This behavior will be removed in future versions of ActiveAdmin. " \ "To fix this warning, move your #{policy_name} policy to the #{default_policy_module} namespace" policy end
def default_policy(subject)
def default_policy(subject) default_policy_class.new(user, subject) end
def default_policy_class
def default_policy_class ActiveAdmin.application.pundit_default_policy && ActiveAdmin.application.pundit_default_policy.constantize end
def default_policy_module
def default_policy_module default_policy_namespace.to_s.camelize end
def default_policy_namespace
def default_policy_namespace ActiveAdmin.application.pundit_policy_namespace end
def format_action(action, subject)
def format_action(action, subject) # https://github.com/varvet/pundit/blob/main/lib/generators/pundit/install/templates/application_policy.rb case action when Auth::READ then subject.is_a?(Class) ? :index? : :show? when Auth::DESTROY then subject.is_a?(Class) ? :destroy_all? : :destroy? else "#{action}?" end end
def namespace(object)
def namespace(object) if default_policy_namespace && !object.class.to_s.start_with?("#{default_policy_module}::") [default_policy_namespace.to_sym, object] else object end end
def policies
def policies @policies ||= {} end
def policy(target)
def policy(target) policies[target] ||= Pundit.policy(user, target) end
def policy_target(subject)
def policy_target(subject) case subject when nil then resource when Class then subject.new else subject end end
def retrieve_policy(subject)
def retrieve_policy(subject) target = policy_target(subject) if (policy = policy(namespace(target)) || compat_policy(subject)) policy elsif default_policy_class default_policy(subject) else raise Pundit::NotDefinedError, "unable to find a compatible policy for `#{target}`" end end
def scope_collection(collection, action = Auth::READ)
def scope_collection(collection, action = Auth::READ) # scoping is appliable only to read/index action # which means there is no way how to scope other actions Pundit.policy_scope!(user, namespace(collection)) rescue Pundit::NotDefinedError => e if default_policy_class && default_policy_class.const_defined?(:Scope) default_policy_class::Scope.new(user, collection).resolve else raise e end end