1
0
Fork 0
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:
Linus Marton 2018-07-03 12:59:23 +02:00 committed by GitHub
commit 1f93b8bfb1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 54 additions and 6 deletions

View file

@ -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:

View file

@ -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.

View file

@ -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

View file

@ -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