diff --git a/lib/pundit/policy_finder.rb b/lib/pundit/policy_finder.rb index 52d8f07..8cead1c 100644 --- a/lib/pundit/policy_finder.rb +++ b/lib/pundit/policy_finder.rb @@ -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 diff --git a/spec/pundit_spec.rb b/spec/pundit_spec.rb index 8977093..2784715 100644 --- a/spec/pundit_spec.rb +++ b/spec/pundit_spec.rb @@ -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