pundit 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +16 -1
- data/lib/pundit/policy_finder.rb +24 -21
- data/lib/pundit/version.rb +1 -1
- data/spec/pundit_spec.rb +57 -0
- metadata +19 -19
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# Pundit
|
2
2
|
|
3
|
+
[](https://travis-ci.org/elabs/pundit)
|
4
|
+
|
3
5
|
Pundit provides a set of helpers which guide you in leveraging regular Ruby
|
4
6
|
classes and object oriented design patterns to build a simple, robust and
|
5
7
|
scaleable authorization system.
|
@@ -193,6 +195,19 @@ You can, and are encouraged to, use this method in views:
|
|
193
195
|
<% end %>
|
194
196
|
```
|
195
197
|
|
198
|
+
## Manually specifying policy classes
|
199
|
+
|
200
|
+
Sometimes you might want to explicitly declare which policy to use for a given
|
201
|
+
class, instead of letting Pundit infer it. This can be done like so:
|
202
|
+
|
203
|
+
``` ruby
|
204
|
+
class Post
|
205
|
+
def self.policy_class
|
206
|
+
PostablePolicyClass
|
207
|
+
end
|
208
|
+
end
|
209
|
+
```
|
210
|
+
|
196
211
|
## Just plain old Ruby
|
197
212
|
|
198
213
|
As you can see, Pundit doesn't do anything you couldn't have easily done
|
@@ -230,7 +245,7 @@ got through. This way you can fail more gracefully.
|
|
230
245
|
``` ruby
|
231
246
|
class ApplicationPolicy
|
232
247
|
def initialize(user, record)
|
233
|
-
raise Pundit::
|
248
|
+
raise Pundit::NotAuthorizedError, "must be logged in" unless user
|
234
249
|
@user = user
|
235
250
|
@record = record
|
236
251
|
end
|
data/lib/pundit/policy_finder.rb
CHANGED
@@ -6,44 +6,47 @@ module Pundit
|
|
6
6
|
@object = object
|
7
7
|
end
|
8
8
|
|
9
|
-
def name
|
10
|
-
if object.respond_to?(:model_name)
|
11
|
-
object.model_name.to_s
|
12
|
-
elsif object.class.respond_to?(:model_name)
|
13
|
-
object.class.model_name.to_s
|
14
|
-
elsif object.is_a?(Class)
|
15
|
-
object.to_s
|
16
|
-
else
|
17
|
-
object.class.to_s
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
9
|
def scope
|
22
|
-
|
10
|
+
policy::Scope if policy
|
23
11
|
rescue NameError
|
24
12
|
nil
|
25
13
|
end
|
26
14
|
|
27
15
|
def policy
|
28
|
-
|
16
|
+
klass = find
|
17
|
+
klass = klass.constantize if klass.is_a?(String)
|
18
|
+
klass
|
29
19
|
rescue NameError
|
30
20
|
nil
|
31
21
|
end
|
32
22
|
|
33
23
|
def scope!
|
34
|
-
scope or raise NotDefinedError, "unable to find scope #{
|
24
|
+
scope or raise NotDefinedError, "unable to find scope #{find}::Scope for #{object}"
|
35
25
|
end
|
36
26
|
|
37
27
|
def policy!
|
38
|
-
policy or raise NotDefinedError, "unable to find policy #{
|
28
|
+
policy or raise NotDefinedError, "unable to find policy #{find} for #{object}"
|
39
29
|
end
|
40
30
|
|
41
|
-
|
42
|
-
"#{name}Policy::Scope"
|
43
|
-
end
|
31
|
+
private
|
44
32
|
|
45
|
-
def
|
46
|
-
|
33
|
+
def find
|
34
|
+
if object.respond_to?(:policy_class)
|
35
|
+
object.policy_class
|
36
|
+
elsif object.class.respond_to?(:policy_class)
|
37
|
+
object.class.policy_class
|
38
|
+
else
|
39
|
+
klass = if object.respond_to?(:model_name)
|
40
|
+
object.model_name
|
41
|
+
elsif object.class.respond_to?(:model_name)
|
42
|
+
object.class.model_name
|
43
|
+
elsif object.is_a?(Class)
|
44
|
+
object
|
45
|
+
else
|
46
|
+
object.class
|
47
|
+
end
|
48
|
+
"#{klass}Policy"
|
49
|
+
end
|
47
50
|
end
|
48
51
|
end
|
49
52
|
end
|
data/lib/pundit/version.rb
CHANGED
data/spec/pundit_spec.rb
CHANGED
@@ -34,12 +34,34 @@ class Comment; extend ActiveModel::Naming; end
|
|
34
34
|
|
35
35
|
class Article; end
|
36
36
|
|
37
|
+
class BlogPolicy < Struct.new(:user, :blog); end
|
38
|
+
class Blog; end
|
39
|
+
class ArtificialBlog < Blog
|
40
|
+
def self.policy_class
|
41
|
+
BlogPolicy
|
42
|
+
end
|
43
|
+
end
|
44
|
+
class ArticleTag
|
45
|
+
def self.policy_class
|
46
|
+
Struct.new(:user, :tag) do
|
47
|
+
def show?
|
48
|
+
true
|
49
|
+
end
|
50
|
+
def destroy?
|
51
|
+
false
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
37
57
|
describe Pundit do
|
38
58
|
let(:user) { stub }
|
39
59
|
let(:post) { Post.new(user) }
|
40
60
|
let(:comment) { Comment.new }
|
41
61
|
let(:article) { Article.new }
|
42
62
|
let(:controller) { stub(:current_user => user, :params => { :action => "update" }).tap { |c| c.extend(Pundit) } }
|
63
|
+
let(:artificial_blog) { ArtificialBlog.new }
|
64
|
+
let(:article_tag) { ArticleTag.new }
|
43
65
|
|
44
66
|
describe ".policy_scope" do
|
45
67
|
it "returns an instantiated policy scope given a plain model class" do
|
@@ -67,6 +89,10 @@ describe Pundit do
|
|
67
89
|
it "throws an exception if the given policy scope can't be found" do
|
68
90
|
expect { Pundit.policy_scope!(user, Article) }.to raise_error(Pundit::NotDefinedError)
|
69
91
|
end
|
92
|
+
|
93
|
+
it "throws an exception if the given policy scope can't be found" do
|
94
|
+
expect { Pundit.policy_scope!(user, ArticleTag) }.to raise_error(Pundit::NotDefinedError)
|
95
|
+
end
|
70
96
|
end
|
71
97
|
|
72
98
|
describe ".policy" do
|
@@ -98,6 +124,32 @@ describe Pundit do
|
|
98
124
|
Pundit.policy(user, article).should be_nil
|
99
125
|
Pundit.policy(user, Article).should be_nil
|
100
126
|
end
|
127
|
+
|
128
|
+
describe "with .policy_class set on the model" do
|
129
|
+
it "returns an instantiated policy given a plain model instance" do
|
130
|
+
policy = Pundit.policy(user, artificial_blog)
|
131
|
+
policy.user.should == user
|
132
|
+
policy.blog.should == artificial_blog
|
133
|
+
end
|
134
|
+
|
135
|
+
it "returns an instantiated policy given a plain model class" do
|
136
|
+
policy = Pundit.policy(user, ArtificialBlog)
|
137
|
+
policy.user.should == user
|
138
|
+
policy.blog.should == ArtificialBlog
|
139
|
+
end
|
140
|
+
|
141
|
+
it "returns an instantiated policy given a plain model instance providing an anonymous class" do
|
142
|
+
policy = Pundit.policy(user, article_tag)
|
143
|
+
policy.user.should == user
|
144
|
+
policy.tag.should == article_tag
|
145
|
+
end
|
146
|
+
|
147
|
+
it "returns an instantiated policy given a plain model class providing an anonymous class" do
|
148
|
+
policy = Pundit.policy(user, ArticleTag)
|
149
|
+
policy.user.should == user
|
150
|
+
policy.tag.should == ArticleTag
|
151
|
+
end
|
152
|
+
end
|
101
153
|
end
|
102
154
|
|
103
155
|
describe ".policy!" do
|
@@ -152,6 +204,11 @@ describe Pundit do
|
|
152
204
|
expect { controller.authorize(post, :destroy?) }.to raise_error(Pundit::NotAuthorizedError)
|
153
205
|
end
|
154
206
|
|
207
|
+
it "works with anonymous class policies" do
|
208
|
+
controller.authorize(article_tag, :show?).should be_true
|
209
|
+
expect { controller.authorize(article_tag, :destroy?) }.to raise_error(Pundit::NotAuthorizedError)
|
210
|
+
end
|
211
|
+
|
155
212
|
it "raises an error when the permission check fails" do
|
156
213
|
expect { controller.authorize(Post.new) }.to raise_error(Pundit::NotAuthorizedError)
|
157
214
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pundit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,88 +10,88 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2013-01-08 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rails
|
17
|
+
prerelease: false
|
17
18
|
requirement: !ruby/object:Gem::Requirement
|
18
|
-
none: false
|
19
19
|
requirements:
|
20
20
|
- - ~>
|
21
21
|
- !ruby/object:Gem::Version
|
22
22
|
version: '3.0'
|
23
|
+
none: false
|
23
24
|
type: :runtime
|
24
|
-
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
|
-
none: false
|
27
26
|
requirements:
|
28
27
|
- - ~>
|
29
28
|
- !ruby/object:Gem::Version
|
30
29
|
version: '3.0'
|
30
|
+
none: false
|
31
31
|
- !ruby/object:Gem::Dependency
|
32
32
|
name: rspec
|
33
|
+
prerelease: false
|
33
34
|
requirement: !ruby/object:Gem::Requirement
|
34
|
-
none: false
|
35
35
|
requirements:
|
36
36
|
- - ~>
|
37
37
|
- !ruby/object:Gem::Version
|
38
38
|
version: '2.0'
|
39
|
+
none: false
|
39
40
|
type: :development
|
40
|
-
prerelease: false
|
41
41
|
version_requirements: !ruby/object:Gem::Requirement
|
42
|
-
none: false
|
43
42
|
requirements:
|
44
43
|
- - ~>
|
45
44
|
- !ruby/object:Gem::Version
|
46
45
|
version: '2.0'
|
46
|
+
none: false
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: pry
|
49
|
+
prerelease: false
|
49
50
|
requirement: !ruby/object:Gem::Requirement
|
50
|
-
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
+
none: false
|
55
56
|
type: :development
|
56
|
-
prerelease: false
|
57
57
|
version_requirements: !ruby/object:Gem::Requirement
|
58
|
-
none: false
|
59
58
|
requirements:
|
60
59
|
- - ! '>='
|
61
60
|
- !ruby/object:Gem::Version
|
62
61
|
version: '0'
|
62
|
+
none: false
|
63
63
|
- !ruby/object:Gem::Dependency
|
64
64
|
name: rake
|
65
|
+
prerelease: false
|
65
66
|
requirement: !ruby/object:Gem::Requirement
|
66
|
-
none: false
|
67
67
|
requirements:
|
68
68
|
- - ! '>='
|
69
69
|
- !ruby/object:Gem::Version
|
70
70
|
version: '0'
|
71
|
+
none: false
|
71
72
|
type: :development
|
72
|
-
prerelease: false
|
73
73
|
version_requirements: !ruby/object:Gem::Requirement
|
74
|
-
none: false
|
75
74
|
requirements:
|
76
75
|
- - ! '>='
|
77
76
|
- !ruby/object:Gem::Version
|
78
77
|
version: '0'
|
78
|
+
none: false
|
79
79
|
- !ruby/object:Gem::Dependency
|
80
80
|
name: yard
|
81
|
+
prerelease: false
|
81
82
|
requirement: !ruby/object:Gem::Requirement
|
82
|
-
none: false
|
83
83
|
requirements:
|
84
84
|
- - ! '>='
|
85
85
|
- !ruby/object:Gem::Version
|
86
86
|
version: '0'
|
87
|
+
none: false
|
87
88
|
type: :development
|
88
|
-
prerelease: false
|
89
89
|
version_requirements: !ruby/object:Gem::Requirement
|
90
|
-
none: false
|
91
90
|
requirements:
|
92
91
|
- - ! '>='
|
93
92
|
- !ruby/object:Gem::Version
|
94
93
|
version: '0'
|
94
|
+
none: false
|
95
95
|
description: Object oriented authorization for Rails applications
|
96
96
|
email:
|
97
97
|
- jonas.nicklas@gmail.com
|
@@ -125,17 +125,17 @@ rdoc_options: []
|
|
125
125
|
require_paths:
|
126
126
|
- lib
|
127
127
|
required_ruby_version: !ruby/object:Gem::Requirement
|
128
|
-
none: false
|
129
128
|
requirements:
|
130
129
|
- - ! '>='
|
131
130
|
- !ruby/object:Gem::Version
|
132
131
|
version: '0'
|
133
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
134
132
|
none: false
|
133
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
135
134
|
requirements:
|
136
135
|
- - ! '>='
|
137
136
|
- !ruby/object:Gem::Version
|
138
137
|
version: '0'
|
138
|
+
none: false
|
139
139
|
requirements: []
|
140
140
|
rubyforge_project:
|
141
141
|
rubygems_version: 1.8.24
|