mirror of
https://github.com/varvet/pundit.git
synced 2022-11-09 12:30:11 -05:00
Improvements on .policy_class
support
The `BlogPolicy -> "BlogPolicy" -> "Blog" -> "BlogPolicy" -> BlogPolicy` issue @jnicklas pointed out has been resolved. For example, given ```ruby class BlogPolicy < Struct.new(:user, :blog); end class Blog; end class ArtificialBlog < Blog def self.policy_class BlogPolicy end end ``` The above string manipulation/casting is prevented; the `BlogPolicy` class will be immediately returned to `policy` and on to be evaluated. Anonymous classes are now supported too. For example, given ```ruby class BlogPolicy < Struct.new(:user, :blog); end class Blog; end class ArtificialBlog < Blog def self.policy_class Struct.new(:user, :blog) do def create? true end end end end ``` The `Struct` will be returned and evaluated as any other policy.
This commit is contained in:
parent
4fc13620ee
commit
e65159f26b
2 changed files with 79 additions and 36 deletions
|
@ -6,30 +6,16 @@ module Pundit
|
|||
@object = object
|
||||
end
|
||||
|
||||
def name
|
||||
if object.respond_to?(:policy_class)
|
||||
object.policy_class.name.gsub(/Policy$/, '')
|
||||
elsif object.class.respond_to?(:policy_class)
|
||||
object.class.policy_class.name.gsub(/Policy$/, '')
|
||||
elsif object.respond_to?(:model_name)
|
||||
object.model_name.to_s
|
||||
elsif object.class.respond_to?(:model_name)
|
||||
object.class.model_name.to_s
|
||||
elsif object.is_a?(Class)
|
||||
object.to_s
|
||||
else
|
||||
object.class.to_s
|
||||
end
|
||||
end
|
||||
|
||||
def scope
|
||||
scope_name.constantize
|
||||
policy::Scope
|
||||
rescue NameError
|
||||
nil
|
||||
end
|
||||
|
||||
def policy
|
||||
policy_name.constantize
|
||||
klass = policy_evaluator
|
||||
klass = klass.constantize if klass.is_a?(String)
|
||||
klass
|
||||
rescue NameError
|
||||
nil
|
||||
end
|
||||
|
@ -42,12 +28,33 @@ module Pundit
|
|||
policy or raise NotDefinedError, "unable to find policy #{policy_name} for #{object}"
|
||||
end
|
||||
|
||||
def scope_name
|
||||
"#{name}Policy::Scope"
|
||||
end
|
||||
private
|
||||
def policy_evaluator
|
||||
if object.respond_to?(:policy_class)
|
||||
return object.policy_class
|
||||
elsif object.class.respond_to?(:policy_class)
|
||||
return object.class.policy_class
|
||||
elsif object.respond_to?(:model_name)
|
||||
klass = object.model_name
|
||||
elsif object.class.respond_to?(:model_name)
|
||||
klass = object.class.model_name
|
||||
elsif object.is_a?(Class)
|
||||
klass = object
|
||||
else
|
||||
klass = object.class
|
||||
end
|
||||
|
||||
def policy_name
|
||||
"#{name}Policy"
|
||||
end
|
||||
"#{klass}Policy"
|
||||
end
|
||||
|
||||
def scope_name
|
||||
"#{policy_name}::Scope"
|
||||
end
|
||||
|
||||
def policy_name
|
||||
name = policy_evaluator
|
||||
return name.name unless name.is_a?(String)
|
||||
name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -41,6 +41,18 @@ class ArtificialBlog < Blog
|
|||
BlogPolicy
|
||||
end
|
||||
end
|
||||
class ArticleTag
|
||||
def self.policy_class
|
||||
Struct.new(:user, :tag) do
|
||||
def show?
|
||||
true
|
||||
end
|
||||
def destroy?
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe Pundit do
|
||||
let(:user) { stub }
|
||||
|
@ -49,6 +61,7 @@ describe Pundit do
|
|||
let(:article) { Article.new }
|
||||
let(:controller) { stub(:current_user => user, :params => { :action => "update" }).tap { |c| c.extend(Pundit) } }
|
||||
let(:artificial_blog) { ArtificialBlog.new }
|
||||
let(:article_tag) { ArticleTag.new }
|
||||
|
||||
describe ".policy_scope" do
|
||||
it "returns an instantiated policy scope given a plain model class" do
|
||||
|
@ -76,6 +89,10 @@ describe Pundit do
|
|||
it "throws an exception if the given policy scope can't be found" do
|
||||
expect { Pundit.policy_scope!(user, Article) }.to raise_error(Pundit::NotDefinedError)
|
||||
end
|
||||
|
||||
it "throws an exception if the given policy scope can't be found" do
|
||||
expect { Pundit.policy_scope!(user, ArticleTag) }.to raise_error(Pundit::NotDefinedError)
|
||||
end
|
||||
end
|
||||
|
||||
describe ".policy" do
|
||||
|
@ -85,18 +102,6 @@ describe Pundit do
|
|||
policy.post.should == post
|
||||
end
|
||||
|
||||
it "returns an instantiated policy given a plain model instance with policy_class class method set" do
|
||||
policy = Pundit.policy(user, artificial_blog)
|
||||
policy.user.should == user
|
||||
policy.blog.should == artificial_blog
|
||||
end
|
||||
|
||||
it "returns an instantiated policy given a plain model class with policy_class class method set" do
|
||||
policy = Pundit.policy(user, ArtificialBlog)
|
||||
policy.user.should == user
|
||||
policy.blog.should == ArtificialBlog
|
||||
end
|
||||
|
||||
it "returns an instantiated policy given an active model instance" do
|
||||
policy = Pundit.policy(user, comment)
|
||||
policy.user.should == user
|
||||
|
@ -119,6 +124,32 @@ describe Pundit do
|
|||
Pundit.policy(user, article).should be_nil
|
||||
Pundit.policy(user, Article).should be_nil
|
||||
end
|
||||
|
||||
describe "with .policy_class set on the model" do
|
||||
it "returns an instantiated policy given a plain model instance" do
|
||||
policy = Pundit.policy(user, artificial_blog)
|
||||
policy.user.should == user
|
||||
policy.blog.should == artificial_blog
|
||||
end
|
||||
|
||||
it "returns an instantiated policy given a plain model class" do
|
||||
policy = Pundit.policy(user, ArtificialBlog)
|
||||
policy.user.should == user
|
||||
policy.blog.should == ArtificialBlog
|
||||
end
|
||||
|
||||
it "returns an instantiated policy given a plain model instance providing an anonymous class" do
|
||||
policy = Pundit.policy(user, article_tag)
|
||||
policy.user.should == user
|
||||
policy.tag.should == article_tag
|
||||
end
|
||||
|
||||
it "returns an instantiated policy given a plain model class providing an anonymous class" do
|
||||
policy = Pundit.policy(user, ArticleTag)
|
||||
policy.user.should == user
|
||||
policy.tag.should == ArticleTag
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe ".policy!" do
|
||||
|
@ -173,6 +204,11 @@ describe Pundit do
|
|||
expect { controller.authorize(post, :destroy?) }.to raise_error(Pundit::NotAuthorizedError)
|
||||
end
|
||||
|
||||
it "works with anonymous class policies" do
|
||||
controller.authorize(article_tag, :show?).should be_true
|
||||
expect { controller.authorize(article_tag, :destroy?) }.to raise_error(Pundit::NotAuthorizedError)
|
||||
end
|
||||
|
||||
it "raises an error when the permission check fails" do
|
||||
expect { controller.authorize(Post.new) }.to raise_error(Pundit::NotAuthorizedError)
|
||||
end
|
||||
|
|
Loading…
Add table
Reference in a new issue