pundit 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6dc0e920a5482e8b695a1cc1afd205fdc7752ad2
4
- data.tar.gz: 1354dab74c79e3673cc034ccccea04688e4cb07a
3
+ metadata.gz: 7cddd41b1da668bb3ff0c192972c1e69a590a66a
4
+ data.tar.gz: 3d21909c8ce034f4e5253045e10407b1a275bd01
5
5
  SHA512:
6
- metadata.gz: 0b745c98f6c3aa8376e97f3270ae6f3358339f13eb2fdd57c8adfc0e47f2dee073138866b7df986317d3bd19f6d23c80f7ffb6311a99b97c4f2fe46cb6924e93
7
- data.tar.gz: bad3e8cb1c9c8888abf4b93521100ae0122eeebb19dbaaf1790e6beb20189dac55a7e60c017bf525ea5b7091ff9c2a07b3126bd928e6f8d22ded5b0b1f3e9ab2
6
+ metadata.gz: 7498ab09942c960b5acc81c7ab9b081e7013007621ed53968d52815abd33e9a67310ac46810b1f3ae754755df01b40d90936b99d247854bcebef16b4b4976e9c
7
+ data.tar.gz: de605bb11eed39677a26ec2426347205e134e1cad09044870705ca73dadf26a152328750387cce44b721add47a8992a700020a0bf4b63f940406e5dfa99a0d2d
data/.travis.yml CHANGED
@@ -4,4 +4,4 @@ rvm:
4
4
  - 2.0.0
5
5
  - 2.1.0
6
6
  - jruby-19mode
7
- - rbx-2.2.3
7
+ - rbx
data/CHANGELOG.md ADDED
@@ -0,0 +1,9 @@
1
+ # Pundit
2
+
3
+ ## 0.2.3 (unreleased)
4
+
5
+ - Add CHANGELOG (#107)
6
+
7
+ ## 0.2.2 (2014-02-07)
8
+
9
+ - Add [`pundit_user`](https://github.com/elabs/pundit#customize-pundit-user) (#42)
data/README.md CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  [![Build Status](https://secure.travis-ci.org/elabs/pundit.png?branch=master)](https://travis-ci.org/elabs/pundit)
4
4
  [![Code Climate](https://codeclimate.com/github/elabs/pundit.png)](https://codeclimate.com/github/elabs/pundit)
5
+ [![Inline docs](http://inch-pages.github.io/github/elabs/pundit.png)](http://inch-pages.github.io/github/elabs/pundit)
5
6
 
6
7
  Pundit provides a set of helpers which guide you in leveraging regular Ruby
7
8
  classes and object oriented design patterns to build a simple, robust and
@@ -57,13 +58,16 @@ As you can see, this is just a plain Ruby class. As a convenience, we can inheri
57
58
  from Struct or use Struct.new to define the policy class:
58
59
 
59
60
  ``` ruby
60
- PostPolicy = Struct.new(:user, :post) do
61
+ class PostPolicy < Struct.new(:user, :post)
61
62
  def update?
62
63
  user.admin? or not post.published?
63
64
  end
64
65
  end
65
66
  ```
66
67
 
68
+ You could also use the convenient
69
+ [attr_extras](https://github.com/barsoom/attr_extras) gem.
70
+
67
71
  Pundit makes the following assumptions about this class:
68
72
 
69
73
  - The class has the same name as some kind of model class, only suffixed
@@ -157,8 +161,8 @@ particular user has access to. When using Pundit, you are expected to
157
161
  define a class called a policy scope. It can look something like this:
158
162
 
159
163
  ``` ruby
160
- PostPolicy = Struct.new(:user, :post) do
161
- self::Scope = Struct.new(:user, :scope) do
164
+ class PostPolicy < Struct.new(:user, :post)
165
+ class Scope < Struct.new(:user, :scope)
162
166
  def resolve
163
167
  if user.admin?
164
168
  scope.all
@@ -271,7 +275,10 @@ end
271
275
 
272
276
  ## Rescuing a denied Authorization in Rails
273
277
 
274
- Pundit raises a `Pundit::NotAuthorizedError` you can [rescue_from](http://guides.rubyonrails.org/action_controller_overview.html#rescue-from) in your `ApplicationController`. You can customize the `user_not_authorized` method in every controller.
278
+ Pundit raises a `Pundit::NotAuthorizedError` you can
279
+ [rescue_from](http://guides.rubyonrails.org/action_controller_overview.html#rescue-from)
280
+ in your `ApplicationController`. You can customize the `user_not_authorized`
281
+ method in every controller.
275
282
 
276
283
  ```ruby
277
284
  class ApplicationController < ActionController::Base
@@ -284,11 +291,48 @@ class ApplicationController < ActionController::Base
284
291
 
285
292
  def user_not_authorized
286
293
  flash[:error] = "You are not authorized to perform this action."
287
- redirect_to request.headers["Referer"] || root_path
294
+ redirect_to(request.referrer || root_path)
288
295
  end
289
296
  end
290
297
  ```
291
298
 
299
+ ### Creating custom error messages
300
+
301
+ `NotAuthorizedError`s provide information on what query (e.g. `:create?`), what
302
+ record (e.g. an instance of `Post`), and what policy (e.g. an instance of
303
+ `PostPolicy`) caused the error to be raised.
304
+
305
+ One way to use these `query`, `record`, and `policy` properties is to connect
306
+ them with `I18n` to generate error messages. Here's how you might go about doing
307
+ that.
308
+
309
+ ```ruby
310
+ class ApplicationController < ActionController::Base
311
+ rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
312
+
313
+ private
314
+
315
+ def user_not_authorized(exception)
316
+ policy_name = exception.policy.class.to_s.underscore
317
+
318
+ flash[:error] = I18n.t "pundit.#{policy_name}.#{exception.query}",
319
+ default: 'You cannot perform this action.'
320
+ redirect_to(request.referrer || root_path)
321
+ end
322
+ end
323
+ ```
324
+
325
+ ```yaml
326
+ en:
327
+ pundit:
328
+ post_policy:
329
+ update?: 'You cannot edit this post!'
330
+ create?: 'You cannot create posts!'
331
+ ```
332
+
333
+ Of course, this is just an example. Pundit is agnostic as to how you implement
334
+ your error messaging.
335
+
292
336
  ## Manually retrieving policies and scopes
293
337
 
294
338
  Sometimes you want to retrieve a policy for a record outside the controller or
@@ -422,6 +466,7 @@ based on what is or is not authorized.
422
466
 
423
467
  # External Resources
424
468
 
469
+ - [RailsApps Example Application: Pundit and Devise](https://github.com/RailsApps/rails-devise-pundit)
425
470
  - [Migrating to Pundit from CanCan](http://blog.carbonfive.com/2013/10/21/migrating-to-pundit-from-cancan/)
426
471
  - [Testing Pundit Policies with RSpec](http://thunderboltlabs.com/blog/2013/03/27/testing-pundit-policies-with-rspec/)
427
472
 
data/lib/pundit.rb CHANGED
@@ -5,7 +5,10 @@ require "active_support/core_ext/string/inflections"
5
5
  require "active_support/core_ext/object/blank"
6
6
 
7
7
  module Pundit
8
- class NotAuthorizedError < StandardError; end
8
+ class NotAuthorizedError < StandardError
9
+ attr_accessor :query, :record, :policy
10
+ end
11
+ class AuthorizationNotPerformedError < StandardError; end
9
12
  class NotDefinedError < StandardError; end
10
13
 
11
14
  extend ActiveSupport::Concern
@@ -37,6 +40,10 @@ module Pundit
37
40
  helper_method :pundit_user
38
41
  end
39
42
  if respond_to?(:hide_action)
43
+ hide_action :policy_scope
44
+ hide_action :policy_scope=
45
+ hide_action :policy
46
+ hide_action :policy=
40
47
  hide_action :authorize
41
48
  hide_action :verify_authorized
42
49
  hide_action :verify_policy_scoped
@@ -45,19 +52,25 @@ module Pundit
45
52
  end
46
53
 
47
54
  def verify_authorized
48
- raise NotAuthorizedError unless @_policy_authorized
55
+ raise AuthorizationNotPerformedError unless @_policy_authorized
49
56
  end
50
57
 
51
58
  def verify_policy_scoped
52
- raise NotAuthorizedError unless @_policy_scoped
59
+ raise AuthorizationNotPerformedError unless @_policy_scoped
53
60
  end
54
61
 
55
62
  def authorize(record, query=nil)
56
63
  query ||= params[:action].to_s + "?"
57
64
  @_policy_authorized = true
58
- unless policy(record).public_send(query)
59
- raise NotAuthorizedError, "not allowed to #{query} this #{record}"
65
+
66
+ policy = policy(record)
67
+ unless policy.public_send(query)
68
+ error = NotAuthorizedError.new("not allowed to #{query} this #{record}")
69
+ error.query, error.record, error.policy = query, record, policy
70
+
71
+ raise error
60
72
  end
73
+
61
74
  true
62
75
  end
63
76
 
data/lib/pundit/rspec.rb CHANGED
@@ -21,7 +21,8 @@ module Pundit
21
21
  end
22
22
 
23
23
  def permissions
24
- example.metadata[:permissions]
24
+ current_example = ::RSpec.respond_to?(:current_example) ? ::RSpec.current_example : example
25
+ current_example.metadata[:permissions]
25
26
  end
26
27
  end
27
28
  end
@@ -1,3 +1,3 @@
1
1
  module Pundit
2
- VERSION = "0.2.2"
2
+ VERSION = "0.2.3"
3
3
  end
data/pundit.gemspec CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |gem|
21
21
  gem.add_dependency "activesupport", ">= 3.0.0"
22
22
  gem.add_development_dependency "activerecord", ">= 3.0.0"
23
23
  gem.add_development_dependency "bundler", "~> 1.3"
24
- gem.add_development_dependency "rspec", "~>2.0"
24
+ gem.add_development_dependency "rspec", "~>3.0.0.beta1"
25
25
  gem.add_development_dependency "pry"
26
26
  gem.add_development_dependency "rake"
27
27
  gem.add_development_dependency "yard"
data/spec/pundit_spec.rb CHANGED
@@ -66,25 +66,25 @@ describe Pundit do
66
66
 
67
67
  describe ".policy_scope" do
68
68
  it "returns an instantiated policy scope given a plain model class" do
69
- Pundit.policy_scope(user, Post).should == :published
69
+ expect(Pundit.policy_scope(user, Post)).to eq :published
70
70
  end
71
71
 
72
72
  it "returns an instantiated policy scope given an active model class" do
73
- Pundit.policy_scope(user, Comment).should == Comment
73
+ expect(Pundit.policy_scope(user, Comment)).to eq Comment
74
74
  end
75
75
 
76
76
  it "returns nil if the given policy scope can't be found" do
77
- Pundit.policy_scope(user, Article).should be_nil
77
+ expect(Pundit.policy_scope(user, Article)).to be_nil
78
78
  end
79
79
  end
80
80
 
81
81
  describe ".policy_scope!" do
82
82
  it "returns an instantiated policy scope given a plain model class" do
83
- Pundit.policy_scope!(user, Post).should == :published
83
+ expect(Pundit.policy_scope!(user, Post)).to eq :published
84
84
  end
85
85
 
86
86
  it "returns an instantiated policy scope given an active model class" do
87
- Pundit.policy_scope!(user, Comment).should == Comment
87
+ expect(Pundit.policy_scope!(user, Comment)).to eq Comment
88
88
  end
89
89
 
90
90
  it "throws an exception if the given policy scope can't be found" do
@@ -99,56 +99,56 @@ describe Pundit do
99
99
  describe ".policy" do
100
100
  it "returns an instantiated policy given a plain model instance" do
101
101
  policy = Pundit.policy(user, post)
102
- policy.user.should == user
103
- policy.post.should == post
102
+ expect(policy.user).to eq user
103
+ expect(policy.post).to eq post
104
104
  end
105
105
 
106
106
  it "returns an instantiated policy given an active model instance" do
107
107
  policy = Pundit.policy(user, comment)
108
- policy.user.should == user
109
- policy.comment.should == comment
108
+ expect(policy.user).to eq user
109
+ expect(policy.comment).to eq comment
110
110
  end
111
111
 
112
112
  it "returns an instantiated policy given a plain model class" do
113
113
  policy = Pundit.policy(user, Post)
114
- policy.user.should == user
115
- policy.post.should == Post
114
+ expect(policy.user).to eq user
115
+ expect(policy.post).to eq Post
116
116
  end
117
117
 
118
118
  it "returns an instantiated policy given an active model class" do
119
119
  policy = Pundit.policy(user, Comment)
120
- policy.user.should == user
121
- policy.comment.should == Comment
120
+ expect(policy.user).to eq user
121
+ expect(policy.comment).to eq Comment
122
122
  end
123
123
 
124
124
  it "returns nil if the given policy can't be found" do
125
- Pundit.policy(user, article).should be_nil
126
- Pundit.policy(user, Article).should be_nil
125
+ expect(Pundit.policy(user, article)).to be_nil
126
+ expect(Pundit.policy(user, Article)).to be_nil
127
127
  end
128
128
 
129
129
  describe "with .policy_class set on the model" do
130
130
  it "returns an instantiated policy given a plain model instance" do
131
131
  policy = Pundit.policy(user, artificial_blog)
132
- policy.user.should == user
133
- policy.blog.should == artificial_blog
132
+ expect(policy.user).to eq user
133
+ expect(policy.blog).to eq artificial_blog
134
134
  end
135
135
 
136
136
  it "returns an instantiated policy given a plain model class" do
137
137
  policy = Pundit.policy(user, ArtificialBlog)
138
- policy.user.should == user
139
- policy.blog.should == ArtificialBlog
138
+ expect(policy.user).to eq user
139
+ expect(policy.blog).to eq ArtificialBlog
140
140
  end
141
141
 
142
142
  it "returns an instantiated policy given a plain model instance providing an anonymous class" do
143
143
  policy = Pundit.policy(user, article_tag)
144
- policy.user.should == user
145
- policy.tag.should == article_tag
144
+ expect(policy.user).to eq user
145
+ expect(policy.tag).to eq article_tag
146
146
  end
147
147
 
148
148
  it "returns an instantiated policy given a plain model class providing an anonymous class" do
149
149
  policy = Pundit.policy(user, ArticleTag)
150
- policy.user.should == user
151
- policy.tag.should == ArticleTag
150
+ expect(policy.user).to eq user
151
+ expect(policy.tag).to eq ArticleTag
152
152
  end
153
153
  end
154
154
  end
@@ -156,26 +156,26 @@ describe Pundit do
156
156
  describe ".policy!" do
157
157
  it "returns an instantiated policy given a plain model instance" do
158
158
  policy = Pundit.policy!(user, post)
159
- policy.user.should == user
160
- policy.post.should == post
159
+ expect(policy.user).to eq user
160
+ expect(policy.post).to eq post
161
161
  end
162
162
 
163
163
  it "returns an instantiated policy given an active model instance" do
164
164
  policy = Pundit.policy!(user, comment)
165
- policy.user.should == user
166
- policy.comment.should == comment
165
+ expect(policy.user).to eq user
166
+ expect(policy.comment).to eq comment
167
167
  end
168
168
 
169
169
  it "returns an instantiated policy given a plain model class" do
170
170
  policy = Pundit.policy!(user, Post)
171
- policy.user.should == user
172
- policy.post.should == Post
171
+ expect(policy.user).to eq user
172
+ expect(policy.post).to eq Post
173
173
  end
174
174
 
175
175
  it "returns an instantiated policy given an active model class" do
176
176
  policy = Pundit.policy!(user, Comment)
177
- policy.user.should == user
178
- policy.comment.should == Comment
177
+ expect(policy.user).to eq user
178
+ expect(policy.comment).to eq Comment
179
179
  end
180
180
 
181
181
  it "throws an exception if the given policy can't be found" do
@@ -191,7 +191,7 @@ describe Pundit do
191
191
  end
192
192
 
193
193
  it "raises an exception when not authorized" do
194
- expect { controller.verify_authorized }.to raise_error(Pundit::NotAuthorizedError)
194
+ expect { controller.verify_authorized }.to raise_error(Pundit::AuthorizationNotPerformedError)
195
195
  end
196
196
  end
197
197
 
@@ -202,41 +202,49 @@ describe Pundit do
202
202
  end
203
203
 
204
204
  it "raises an exception when policy_scope is not used" do
205
- expect { controller.verify_policy_scoped }.to raise_error(Pundit::NotAuthorizedError)
205
+ expect { controller.verify_policy_scoped }.to raise_error(Pundit::AuthorizationNotPerformedError)
206
206
  end
207
207
  end
208
208
 
209
209
  describe "#authorize" do
210
210
  it "infers the policy name and authorized based on it" do
211
- controller.authorize(post).should be_true
211
+ expect(controller.authorize(post)).to be_truthy
212
212
  end
213
213
 
214
214
  it "can be given a different permission to check" do
215
- controller.authorize(post, :show?).should be_true
215
+ expect(controller.authorize(post, :show?)).to be_truthy
216
216
  expect { controller.authorize(post, :destroy?) }.to raise_error(Pundit::NotAuthorizedError)
217
217
  end
218
218
 
219
219
  it "works with anonymous class policies" do
220
- controller.authorize(article_tag, :show?).should be_true
220
+ expect(controller.authorize(article_tag, :show?)).to be_truthy
221
221
  expect { controller.authorize(article_tag, :destroy?) }.to raise_error(Pundit::NotAuthorizedError)
222
222
  end
223
223
 
224
224
  it "raises an error when the permission check fails" do
225
225
  expect { controller.authorize(Post.new) }.to raise_error(Pundit::NotAuthorizedError)
226
226
  end
227
+
228
+ it "raises an error with a query and action" do
229
+ expect { controller.authorize(post, :destroy?) }.to raise_error do |error|
230
+ expect(error.query).to eq :destroy?
231
+ expect(error.record).to eq post
232
+ expect(error.policy).to eq controller.policy(post)
233
+ end
234
+ end
227
235
  end
228
236
 
229
237
  describe "#pundit_user" do
230
238
  it 'returns the same thing as current_user' do
231
- controller.pundit_user.should eq controller.current_user
239
+ expect(controller.pundit_user).to eq controller.current_user
232
240
  end
233
241
  end
234
242
 
235
243
  describe ".policy" do
236
244
  it "returns an instantiated policy" do
237
245
  policy = controller.policy(post)
238
- policy.user.should == user
239
- policy.post.should == post
246
+ expect(policy.user).to eq user
247
+ expect(policy.post).to eq post
240
248
  end
241
249
 
242
250
  it "throws an exception if the given policy can't be found" do
@@ -247,13 +255,13 @@ describe Pundit do
247
255
  new_policy = OpenStruct.new
248
256
  controller.policy = new_policy
249
257
 
250
- controller.policy(post).should == new_policy
258
+ expect(controller.policy(post)).to eq new_policy
251
259
  end
252
260
  end
253
261
 
254
262
  describe ".policy_scope" do
255
263
  it "returns an instantiated policy scope" do
256
- controller.policy_scope(Post).should == :published
264
+ expect(controller.policy_scope(Post)).to eq :published
257
265
  end
258
266
 
259
267
  it "throws an exception if the given policy can't be found" do
@@ -264,7 +272,7 @@ describe Pundit do
264
272
  new_scope = OpenStruct.new
265
273
  controller.policy_scope = new_scope
266
274
 
267
- controller.policy_scope(post).should == new_scope
275
+ expect(controller.policy_scope(post)).to eq new_scope
268
276
  end
269
277
  end
270
278
  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.2.2
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonas Nicklas
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-02-07 00:00:00.000000000 Z
12
+ date: 2014-04-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -59,14 +59,14 @@ dependencies:
59
59
  requirements:
60
60
  - - ~>
61
61
  - !ruby/object:Gem::Version
62
- version: '2.0'
62
+ version: 3.0.0.beta1
63
63
  type: :development
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
67
  - - ~>
68
68
  - !ruby/object:Gem::Version
69
- version: '2.0'
69
+ version: 3.0.0.beta1
70
70
  - !ruby/object:Gem::Dependency
71
71
  name: pry
72
72
  requirement: !ruby/object:Gem::Requirement
@@ -119,6 +119,7 @@ extra_rdoc_files: []
119
119
  files:
120
120
  - .gitignore
121
121
  - .travis.yml
122
+ - CHANGELOG.md
122
123
  - Gemfile
123
124
  - LICENSE.txt
124
125
  - README.md