mirror of
https://github.com/varvet/pundit.git
synced 2022-11-09 12:30:11 -05:00
Merge pull request #441 from pablocrivella/allow-overriding-policy-class-on-authorize-method
Allow overriding policy class on authorize method
This commit is contained in:
commit
1f93b8bfb1
4 changed files with 54 additions and 6 deletions
21
README.md
21
README.md
|
@ -133,6 +133,18 @@ def publish
|
|||
end
|
||||
```
|
||||
|
||||
You can pass an argument to override the policy class if necessary. For example:
|
||||
|
||||
```ruby
|
||||
def create
|
||||
@publication = find_publication # assume this method returns any model that behaves like a publication
|
||||
# @publication.class => Post
|
||||
authorize @publication, policy_class: PublicationPolicy
|
||||
@publication.publish!
|
||||
redirect_to @publication
|
||||
end
|
||||
```
|
||||
|
||||
If you don't have an instance for the first argument to `authorize`, then you can pass
|
||||
the class. For example:
|
||||
|
||||
|
@ -271,6 +283,15 @@ def show
|
|||
end
|
||||
```
|
||||
|
||||
Like with the authorize method, you can also override the policy scope class:
|
||||
|
||||
``` ruby
|
||||
def index
|
||||
# publication_class => Post
|
||||
@publications = policy_scope(publication_class, policy_scope_class: PublicationPolicy::Scope)
|
||||
end
|
||||
```
|
||||
|
||||
Just as with your policy, this will automatically infer that you want to use
|
||||
the `PostPolicy::Scope` class, it will instantiate this class and call
|
||||
`resolve` on the instance. In this case it is a shortcut for doing:
|
||||
|
|
|
@ -61,10 +61,11 @@ module Pundit
|
|||
# @param user [Object] the user that initiated the 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?`)
|
||||
# @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(user, record, query)
|
||||
policy = policy!(user, record)
|
||||
def authorize(user, record, query, policy_class: nil)
|
||||
policy = policy_class ? policy_class.new(user, record) : policy!(user, record)
|
||||
|
||||
raise NotAuthorizedError, query: query, record: record, policy: policy unless policy.public_send(query)
|
||||
|
||||
|
@ -195,14 +196,15 @@ protected
|
|||
# @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)
|
||||
def authorize(record, query = nil, policy_class: nil)
|
||||
query ||= "#{action_name}?"
|
||||
|
||||
@_pundit_policy_authorized = true
|
||||
|
||||
policy = policy(record)
|
||||
policy = policy_class ? policy_class.new(pundit_user, record) : policy(record)
|
||||
|
||||
raise NotAuthorizedError, query: query, record: record, policy: policy unless policy.public_send(query)
|
||||
|
||||
|
@ -229,10 +231,11 @@ protected
|
|||
#
|
||||
# @see https://github.com/elabs/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)
|
||||
def policy_scope(scope, policy_scope_class: nil)
|
||||
@_pundit_policy_scoped = true
|
||||
pundit_policy_scope(scope)
|
||||
policy_scope_class ? policy_scope_class.new(pundit_user, scope).resolve : pundit_policy_scope(scope)
|
||||
end
|
||||
|
||||
# Retrieves the policy for the given record.
|
||||
|
|
|
@ -22,6 +22,10 @@ describe Pundit do
|
|||
expect(Pundit.authorize(user, post, :update?)).to be_truthy
|
||||
end
|
||||
|
||||
it "can be given a different policy class" do
|
||||
expect(Pundit.authorize(user, post, :create?, policy_class: PublicationPolicy)).to be_truthy
|
||||
end
|
||||
|
||||
it "works with anonymous class policies" do
|
||||
expect(Pundit.authorize(user, article_tag, :show?)).to be_truthy
|
||||
expect { Pundit.authorize(user, article_tag, :destroy?) }.to raise_error(Pundit::NotAuthorizedError)
|
||||
|
@ -405,6 +409,10 @@ describe Pundit do
|
|||
expect { controller.authorize(post, :destroy?) }.to raise_error(Pundit::NotAuthorizedError)
|
||||
end
|
||||
|
||||
it "can be given a different policy class" do
|
||||
expect(controller.authorize(post, :create?, policy_class: PublicationPolicy)).to be_truthy
|
||||
end
|
||||
|
||||
it "works with anonymous class policies" do
|
||||
expect(controller.authorize(article_tag, :show?)).to be_truthy
|
||||
expect { controller.authorize(article_tag, :destroy?) }.to raise_error(Pundit::NotAuthorizedError)
|
||||
|
@ -481,6 +489,10 @@ describe Pundit do
|
|||
expect(controller.policy_scope(Post)).to eq :published
|
||||
end
|
||||
|
||||
it "allows policy scope class to be overriden" do
|
||||
expect(controller.policy_scope(Post, policy_scope_class: PublicationPolicy::Scope)).to eq :published
|
||||
end
|
||||
|
||||
it "throws an exception if the given policy can't be found" do
|
||||
expect { controller.policy_scope(Article) }.to raise_error(Pundit::NotDefinedError)
|
||||
end
|
||||
|
|
|
@ -110,6 +110,18 @@ class CommentPolicy < Struct.new(:user, :comment)
|
|||
end
|
||||
end
|
||||
|
||||
class PublicationPolicy < Struct.new(:user, :publication)
|
||||
class Scope < Struct.new(:user, :scope)
|
||||
def resolve
|
||||
scope.published
|
||||
end
|
||||
end
|
||||
|
||||
def create?
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
class Comment
|
||||
extend ActiveModel::Naming
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue