lib/pundit.rb in pundit-2.1.1 vs lib/pundit.rb in pundit-2.2.0
- old
+ new
@@ -5,10 +5,11 @@
require "active_support/concern"
require "active_support/core_ext/string/inflections"
require "active_support/core_ext/object/blank"
require "active_support/core_ext/module/introspection"
require "active_support/dependencies/autoload"
+require "pundit/authorization"
# @api private
# To avoid name clashes with common Error naming when mixing in Pundit,
# keep it here with compact class style definition.
class Pundit::Error < StandardError; end # rubocop:disable Style/ClassAndModuleChildren
@@ -51,29 +52,40 @@
class PolicyScopingNotPerformedError < AuthorizationNotPerformedError; end
# Error that will be raised if a policy or policy scope is not defined.
class NotDefinedError < Error; end
- extend ActiveSupport::Concern
+ def self.included(base)
+ ActiveSupport::Deprecation.warn <<~WARNING.strip_heredoc
+ 'include Pundit' is deprecated. Please use 'include Pundit::Authorization' instead.
+ WARNING
+ base.include Authorization
+ end
class << self
# Retrieves the policy for the given record, initializing it with the
# record and user and finally throwing an error if the user is not
# authorized to perform the given action.
#
# @param user [Object] the user that initiated the action
- # @param record [Object] the object we're checking permissions of
+ # @param possibly_namespaced_record [Object, Array] the object we're checking permissions of
# @param query [Symbol, String] the predicate method to check on the policy (e.g. `:show?`)
# @param policy_class [Class] the policy class we want to force use of
+ # @param cache [#[], #[]=] a Hash-like object to cache the found policy instance in
# @raise [NotAuthorizedError] if the given query method returned false
# @return [Object] Always returns the passed object record
- def authorize(user, record, query, policy_class: nil)
- policy = policy_class ? policy_class.new(user, record) : policy!(user, record)
+ def authorize(user, possibly_namespaced_record, query, policy_class: nil, cache: {})
+ record = pundit_model(possibly_namespaced_record)
+ policy = if policy_class
+ policy_class.new(user, record)
+ else
+ cache[possibly_namespaced_record] ||= policy!(user, possibly_namespaced_record)
+ end
raise NotAuthorizedError, query: query, record: record, policy: policy unless policy.public_send(query)
- record.is_a?(Array) ? record.last : record
+ record
end
# Retrieves the policy scope for the given record.
#
# @see https://github.com/varvet/pundit#scopes
@@ -154,172 +166,7 @@
# @api private
module Helper
def policy_scope(scope)
pundit_policy_scope(scope)
end
- end
-
- included do
- helper Helper if respond_to?(:helper)
- if respond_to?(:helper_method)
- helper_method :policy
- helper_method :pundit_policy_scope
- helper_method :pundit_user
- end
- end
-
- protected
-
- # @return [Boolean] whether authorization has been performed, i.e. whether
- # one {#authorize} or {#skip_authorization} has been called
- def pundit_policy_authorized?
- !!@_pundit_policy_authorized
- end
-
- # @return [Boolean] whether policy scoping has been performed, i.e. whether
- # one {#policy_scope} or {#skip_policy_scope} has been called
- def pundit_policy_scoped?
- !!@_pundit_policy_scoped
- end
-
- # Raises an error if authorization has not been performed, usually used as an
- # `after_action` filter to prevent programmer error in forgetting to call
- # {#authorize} or {#skip_authorization}.
- #
- # @see https://github.com/varvet/pundit#ensuring-policies-and-scopes-are-used
- # @raise [AuthorizationNotPerformedError] if authorization has not been performed
- # @return [void]
- def verify_authorized
- raise AuthorizationNotPerformedError, self.class unless pundit_policy_authorized?
- end
-
- # Raises an error if policy scoping has not been performed, usually used as an
- # `after_action` filter to prevent programmer error in forgetting to call
- # {#policy_scope} or {#skip_policy_scope} in index actions.
- #
- # @see https://github.com/varvet/pundit#ensuring-policies-and-scopes-are-used
- # @raise [AuthorizationNotPerformedError] if policy scoping has not been performed
- # @return [void]
- def verify_policy_scoped
- raise PolicyScopingNotPerformedError, self.class unless pundit_policy_scoped?
- end
-
- # Retrieves the policy for the given record, initializing it with the record
- # and current user and finally throwing an error if the user is not
- # authorized to perform the given action.
- #
- # @param record [Object] the object we're checking permissions of
- # @param query [Symbol, String] the predicate method to check on the policy (e.g. `:show?`).
- # If omitted then this defaults to the Rails controller action name.
- # @param policy_class [Class] the policy class we want to force use of
- # @raise [NotAuthorizedError] if the given query method returned false
- # @return [Object] Always returns the passed object record
- def authorize(record, query = nil, policy_class: nil)
- query ||= "#{action_name}?"
-
- @_pundit_policy_authorized = true
-
- policy = policy_class ? policy_class.new(pundit_user, record) : policy(record)
-
- raise NotAuthorizedError, query: query, record: record, policy: policy unless policy.public_send(query)
-
- record.is_a?(Array) ? record.last : record
- end
-
- # Allow this action not to perform authorization.
- #
- # @see https://github.com/varvet/pundit#ensuring-policies-and-scopes-are-used
- # @return [void]
- def skip_authorization
- @_pundit_policy_authorized = true
- end
-
- # Allow this action not to perform policy scoping.
- #
- # @see https://github.com/varvet/pundit#ensuring-policies-and-scopes-are-used
- # @return [void]
- def skip_policy_scope
- @_pundit_policy_scoped = true
- end
-
- # Retrieves the policy scope for the given record.
- #
- # @see https://github.com/varvet/pundit#scopes
- # @param scope [Object] the object we're retrieving the policy scope for
- # @param policy_scope_class [Class] the policy scope class we want to force use of
- # @return [Scope{#resolve}, nil] instance of scope class which can resolve to a scope
- def policy_scope(scope, policy_scope_class: nil)
- @_pundit_policy_scoped = true
- policy_scope_class ? policy_scope_class.new(pundit_user, scope).resolve : pundit_policy_scope(scope)
- end
-
- # Retrieves the policy for the given record.
- #
- # @see https://github.com/varvet/pundit#policies
- # @param record [Object] the object we're retrieving the policy for
- # @return [Object, nil] instance of policy class with query methods
- def policy(record)
- policies[record] ||= Pundit.policy!(pundit_user, record)
- end
-
- # Retrieves a set of permitted attributes from the policy by instantiating
- # the policy class for the given record and calling `permitted_attributes` on
- # it, or `permitted_attributes_for_{action}` if `action` is defined. It then infers
- # what key the record should have in the params hash and retrieves the
- # permitted attributes from the params hash under that key.
- #
- # @see https://github.com/varvet/pundit#strong-parameters
- # @param record [Object] the object we're retrieving permitted attributes for
- # @param action [Symbol, String] the name of the action being performed on the record (e.g. `:update`).
- # If omitted then this defaults to the Rails controller action name.
- # @return [Hash{String => Object}] the permitted attributes
- def permitted_attributes(record, action = action_name)
- policy = policy(record)
- method_name = if policy.respond_to?("permitted_attributes_for_#{action}")
- "permitted_attributes_for_#{action}"
- else
- "permitted_attributes"
- end
- pundit_params_for(record).permit(*policy.public_send(method_name))
- end
-
- # Retrieves the params for the given record.
- #
- # @param record [Object] the object we're retrieving params for
- # @return [ActionController::Parameters] the params
- def pundit_params_for(record)
- params.require(PolicyFinder.new(record).param_key)
- end
-
- # Cache of policies. You should not rely on this method.
- #
- # @api private
- # rubocop:disable Naming/MemoizedInstanceVariableName
- def policies
- @_pundit_policies ||= {}
- end
- # rubocop:enable Naming/MemoizedInstanceVariableName
-
- # Cache of policy scope. You should not rely on this method.
- #
- # @api private
- # rubocop:disable Naming/MemoizedInstanceVariableName
- def policy_scopes
- @_pundit_policy_scopes ||= {}
- end
- # rubocop:enable Naming/MemoizedInstanceVariableName
-
- # Hook method which allows customizing which user is passed to policies and
- # scopes initialized by {#authorize}, {#policy} and {#policy_scope}.
- #
- # @see https://github.com/varvet/pundit#customize-pundit-user
- # @return [Object] the user object to be used with pundit
- def pundit_user
- current_user
- end
-
- private
-
- def pundit_policy_scope(scope)
- policy_scopes[scope] ||= Pundit.policy_scope!(pundit_user, scope)
end
end