parent
cdeb0fde8f
commit
9855bdf97a
115
lib/pundit.rb
115
lib/pundit.rb
|
@ -6,10 +6,17 @@ require "active_support/core_ext/object/blank"
|
||||||
require "active_support/core_ext/module/introspection"
|
require "active_support/core_ext/module/introspection"
|
||||||
require "active_support/dependencies/autoload"
|
require "active_support/dependencies/autoload"
|
||||||
|
|
||||||
|
# @api public
|
||||||
module Pundit
|
module Pundit
|
||||||
SUFFIX = "Policy"
|
SUFFIX = "Policy"
|
||||||
|
|
||||||
|
# @api private
|
||||||
|
module Generators; end
|
||||||
|
|
||||||
|
# @api private
|
||||||
class Error < StandardError; end
|
class Error < StandardError; end
|
||||||
|
|
||||||
|
# Error that will be raiser when authorization has failed
|
||||||
class NotAuthorizedError < Error
|
class NotAuthorizedError < Error
|
||||||
attr_reader :query, :record, :policy
|
attr_reader :query, :record, :policy
|
||||||
|
|
||||||
|
@ -27,13 +34,30 @@ module Pundit
|
||||||
super(message)
|
super(message)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Error that will be raised if a controller action has not called the
|
||||||
|
# `authorize` or `skip_authorization` methods.
|
||||||
class AuthorizationNotPerformedError < Error; end
|
class AuthorizationNotPerformedError < Error; end
|
||||||
|
|
||||||
|
# Error that will be raised if a controller action has not called the
|
||||||
|
# `policy_scope` or `skip_policy_scope` methods.
|
||||||
class PolicyScopingNotPerformedError < AuthorizationNotPerformedError; end
|
class PolicyScopingNotPerformedError < AuthorizationNotPerformedError; end
|
||||||
|
|
||||||
|
# Error that will be raised if a policy or policy scope is not defined.
|
||||||
class NotDefinedError < Error; end
|
class NotDefinedError < Error; end
|
||||||
|
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
class << self
|
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 record [Symbol] the query method to check on the policy (e.g. `:show?`)
|
||||||
|
# @raise [NotAuthorizedError] if the given query method returned false
|
||||||
|
# @return [true] Always returns true
|
||||||
def authorize(user, record, query)
|
def authorize(user, record, query)
|
||||||
policy = policy!(user, record)
|
policy = policy!(user, record)
|
||||||
|
|
||||||
|
@ -44,25 +68,52 @@ module Pundit
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Retrieves the policy scope for the given record.
|
||||||
|
#
|
||||||
|
# @see https://github.com/elabs/pundit#scopes
|
||||||
|
# @param user [Object] the user that initiated the action
|
||||||
|
# @param record [Object] the object we're retrieving the policy scope for
|
||||||
|
# @return [Scope{#resolve}, nil] instance of scope class which can resolve to a scope
|
||||||
def policy_scope(user, scope)
|
def policy_scope(user, scope)
|
||||||
policy_scope = PolicyFinder.new(scope).scope
|
policy_scope = PolicyFinder.new(scope).scope
|
||||||
policy_scope.new(user, scope).resolve if policy_scope
|
policy_scope.new(user, scope).resolve if policy_scope
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Retrieves the policy scope for the given record.
|
||||||
|
#
|
||||||
|
# @see https://github.com/elabs/pundit#scopes
|
||||||
|
# @param user [Object] the user that initiated the action
|
||||||
|
# @param record [Object] the object we're retrieving the policy scope for
|
||||||
|
# @raise [NotDefinedError] if the policy scope cannot be found
|
||||||
|
# @return [Scope{#resolve}] instance of scope class which can resolve to a scope
|
||||||
def policy_scope!(user, scope)
|
def policy_scope!(user, scope)
|
||||||
PolicyFinder.new(scope).scope!.new(user, scope).resolve
|
PolicyFinder.new(scope).scope!.new(user, scope).resolve
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Retrieves the policy for the given record.
|
||||||
|
#
|
||||||
|
# @see https://github.com/elabs/pundit#policies
|
||||||
|
# @param user [Object] the user that initiated the action
|
||||||
|
# @param record [Object] the object we're retrieving the policy for
|
||||||
|
# @return [Object, nil] instance of policy class with query methods
|
||||||
def policy(user, record)
|
def policy(user, record)
|
||||||
policy = PolicyFinder.new(record).policy
|
policy = PolicyFinder.new(record).policy
|
||||||
policy.new(user, record) if policy
|
policy.new(user, record) if policy
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Retrieves the policy for the given record.
|
||||||
|
#
|
||||||
|
# @see https://github.com/elabs/pundit#policies
|
||||||
|
# @param user [Object] the user that initiated the action
|
||||||
|
# @param record [Object] the object we're retrieving the policy for
|
||||||
|
# @raise [NotDefinedError] if the policy cannot be found
|
||||||
|
# @return [Object] instance of policy class with query methods
|
||||||
def policy!(user, record)
|
def policy!(user, record)
|
||||||
PolicyFinder.new(record).policy!.new(user, record)
|
PolicyFinder.new(record).policy!.new(user, record)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# @api private
|
||||||
module Helper
|
module Helper
|
||||||
def policy_scope(scope)
|
def policy_scope(scope)
|
||||||
pundit_policy_scope(scope)
|
pundit_policy_scope(scope)
|
||||||
|
@ -93,22 +144,48 @@ module Pundit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# @return [Boolean] whether authorization has been performed, i.e. whether
|
||||||
|
# one {#authorize} or {#skip_authorization} has been called
|
||||||
def pundit_policy_authorized?
|
def pundit_policy_authorized?
|
||||||
!!@_pundit_policy_authorized
|
!!@_pundit_policy_authorized
|
||||||
end
|
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?
|
def pundit_policy_scoped?
|
||||||
!!@_pundit_policy_scoped
|
!!@_pundit_policy_scoped
|
||||||
end
|
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/elabs/pundit#ensuring-policies-are-used
|
||||||
|
# @raise [AuthorizationNotPerformedError] if authorization has not been performed
|
||||||
|
# @return [void]
|
||||||
def verify_authorized
|
def verify_authorized
|
||||||
raise AuthorizationNotPerformedError, self.class unless pundit_policy_authorized?
|
raise AuthorizationNotPerformedError, self.class unless pundit_policy_authorized?
|
||||||
end
|
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/elabs/pundit#ensuring-policies-are-used
|
||||||
|
# @raise [AuthorizationNotPerformedError] if policy scoping has not been performed
|
||||||
|
# @return [void]
|
||||||
def verify_policy_scoped
|
def verify_policy_scoped
|
||||||
raise PolicyScopingNotPerformedError, self.class unless pundit_policy_scoped?
|
raise PolicyScopingNotPerformedError, self.class unless pundit_policy_scoped?
|
||||||
end
|
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 record [Symbol, nil] the query method to check on the policy (e.g. `:show?`)
|
||||||
|
# @raise [NotAuthorizedError] if the given query method returned false
|
||||||
|
# @return [true] Always returns true
|
||||||
def authorize(record, query = nil)
|
def authorize(record, query = nil)
|
||||||
query ||= params[:action].to_s + "?"
|
query ||= params[:action].to_s + "?"
|
||||||
|
|
||||||
|
@ -123,23 +200,50 @@ module Pundit
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Allow this action not to perform authorization.
|
||||||
|
#
|
||||||
|
# @see https://github.com/elabs/pundit#ensuring-policies-are-used
|
||||||
|
# @return [void]
|
||||||
def skip_authorization
|
def skip_authorization
|
||||||
@_pundit_policy_authorized = true
|
@_pundit_policy_authorized = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Allow this action not to perform policy scoping.
|
||||||
|
#
|
||||||
|
# @see https://github.com/elabs/pundit#ensuring-policies-are-used
|
||||||
|
# @return [void]
|
||||||
def skip_policy_scope
|
def skip_policy_scope
|
||||||
@_pundit_policy_scoped = true
|
@_pundit_policy_scoped = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Retrieves the policy scope for the given record.
|
||||||
|
#
|
||||||
|
# @see https://github.com/elabs/pundit#scopes
|
||||||
|
# @param record [Object] the object we're retrieving the policy scope for
|
||||||
|
# @return [Scope{#resolve}, nil] instance of scope class which can resolve to a scope
|
||||||
def policy_scope(scope)
|
def policy_scope(scope)
|
||||||
@_pundit_policy_scoped = true
|
@_pundit_policy_scoped = true
|
||||||
pundit_policy_scope(scope)
|
pundit_policy_scope(scope)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Retrieves the policy for the given record.
|
||||||
|
#
|
||||||
|
# @see https://github.com/elabs/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)
|
def policy(record)
|
||||||
policies[record] ||= Pundit.policy!(pundit_user, record)
|
policies[record] ||= Pundit.policy!(pundit_user, record)
|
||||||
end
|
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 it 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/elabs/pundit#strong-parameters
|
||||||
|
# @param record [Object] the object we're retrieving permitted attributes for
|
||||||
|
# @return [Hash{String => Object}] the permitted attributes
|
||||||
def permitted_attributes(record, action = params[:action])
|
def permitted_attributes(record, action = params[:action])
|
||||||
param_key = PolicyFinder.new(record).param_key
|
param_key = PolicyFinder.new(record).param_key
|
||||||
policy = policy(record)
|
policy = policy(record)
|
||||||
|
@ -151,14 +255,25 @@ module Pundit
|
||||||
params.require(param_key).permit(policy.public_send(method_name))
|
params.require(param_key).permit(policy.public_send(method_name))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Cache of policies. You should not rely on this method.
|
||||||
|
#
|
||||||
|
# @api private
|
||||||
def policies
|
def policies
|
||||||
@_pundit_policies ||= {}
|
@_pundit_policies ||= {}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Cache of policy scope. You should not rely on this method.
|
||||||
|
#
|
||||||
|
# @api private
|
||||||
def policy_scopes
|
def policy_scopes
|
||||||
@_pundit_policy_scopes ||= {}
|
@_pundit_policy_scopes ||= {}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Hook method which allows customizing which user is passed to policies and
|
||||||
|
# scopes initialized by {#authorize}, {#policy} and {#policy_scope}.
|
||||||
|
#
|
||||||
|
# @see https://github.com/elabs/pundit#customize-pundit-user
|
||||||
|
# @return [Object] the user object to be used with pundit
|
||||||
def pundit_user
|
def pundit_user
|
||||||
current_user
|
current_user
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,13 +10,13 @@ module Pundit
|
||||||
class PolicyFinder
|
class PolicyFinder
|
||||||
attr_reader :object
|
attr_reader :object
|
||||||
|
|
||||||
# @param object [any]
|
# @param object [any] the object to find policy and scope classes for
|
||||||
#
|
#
|
||||||
def initialize(object)
|
def initialize(object)
|
||||||
@object = object
|
@object = object
|
||||||
end
|
end
|
||||||
|
|
||||||
# @return [nil, Scope{#resolve}]
|
# @return [nil, Scope{#resolve}] scope class which can resolve to a scope
|
||||||
# @see https://github.com/elabs/pundit#scopes
|
# @see https://github.com/elabs/pundit#scopes
|
||||||
# @example
|
# @example
|
||||||
# scope = finder.scope #=> UserPolicy::Scope
|
# scope = finder.scope #=> UserPolicy::Scope
|
||||||
|
@ -43,7 +43,7 @@ module Pundit
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
# @return [Scope{#resolve}]
|
# @return [Scope{#resolve}] scope class which can resolve to a scope
|
||||||
# @raise [NotDefinedError] if scope could not be determined
|
# @raise [NotDefinedError] if scope could not be determined
|
||||||
#
|
#
|
||||||
def scope!
|
def scope!
|
||||||
|
@ -73,9 +73,6 @@ module Pundit
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
# @return [String] policy class name
|
|
||||||
# @api public
|
|
||||||
#
|
|
||||||
def find
|
def find
|
||||||
if object.nil?
|
if object.nil?
|
||||||
nil
|
nil
|
||||||
|
|
Loading…
Reference in New Issue