pundit 1.1.0 → 2.1.0

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
- SHA1:
3
- metadata.gz: a2c188098c86ad5a0804044f80219014564501ef
4
- data.tar.gz: 2ab7f79275d9ae66e5d04cf980c11e2c2983a4ef
2
+ SHA256:
3
+ metadata.gz: 371516754ff155f90b2093a0ce80aacf097ab555027b19ea22b7c823de72a66a
4
+ data.tar.gz: 41e69a7d6a317b46ad35d1d1485d2119b443b8a430e5c78e62935ec502c7d08f
5
5
  SHA512:
6
- metadata.gz: 55fbbf71ad514c0cfe4f8933dea59915314f749efa53ab5579f2da9dfcf2b4786343cefa53d3a35e26f4a346776c1c513884595a39561d280b259e6b6fb9b31a
7
- data.tar.gz: bbcf9417801b22deac78afe2d5ea8a268193daf0e011f861006c25b1d0124d1f462aa37d4d38e623b9d438cb29ceb52b250575118e053862b74561795bbdd7a4
6
+ metadata.gz: c77a792bec5d87f487fd3ee419d00745dcab754bd1bd38504d9987b71d80be3bd32fb1aab8419a8e63ef3c3718e1bd8a255ff0117be8f8a5c743c221d87fccdd
7
+ data.tar.gz: 3086b4036cdbafb499f462f22405f185c83d12c8d8175136531dd053733320574b3d5d05c8379895940d854d54d7abb59d6a0958a9d0e6fdfc03f7691883c3ab
data/.rubocop.yml CHANGED
@@ -1,14 +1,22 @@
1
1
  AllCops:
2
+ DisplayCopNames: true
3
+ TargetRubyVersion: 2.2
2
4
  Exclude:
3
5
  - "gemfiles/**/*"
4
6
  - "vendor/**/*"
5
7
  - "lib/generators/**/*"
6
8
 
9
+ Metrics/BlockLength:
10
+ Exclude:
11
+ - "**/*_spec.rb"
12
+
7
13
  Metrics/MethodLength:
8
14
  Max: 40
9
15
 
10
16
  Metrics/ModuleLength:
11
17
  Max: 200
18
+ Exclude:
19
+ - "**/*_spec.rb"
12
20
 
13
21
  Metrics/LineLength:
14
22
  Max: 120
@@ -22,74 +30,47 @@ Metrics/CyclomaticComplexity:
22
30
  Metrics/PerceivedComplexity:
23
31
  Enabled: false
24
32
 
25
- Style/StructInheritance:
26
- Enabled: false
27
-
28
- Style/AlignParameters:
33
+ Layout/AlignParameters:
29
34
  EnforcedStyle: with_fixed_indentation
30
35
 
31
- Style/StringLiterals:
32
- EnforcedStyle: double_quotes
33
-
34
- Style/StringLiteralsInInterpolation:
35
- EnforcedStyle: double_quotes
36
-
37
- Style/ClosingParenthesisIndentation:
38
- Enabled: false
39
-
40
- Style/OneLineConditional:
41
- Enabled: false
42
-
43
- Style/AndOr:
44
- Enabled: false
45
-
46
- Style/Not:
47
- Enabled: false
48
-
49
- Documentation:
50
- Enabled: false # TODO: Enable again once we have more docs
51
-
52
- Style/CaseIndentation:
53
- IndentWhenRelativeTo: case
36
+ Layout/CaseIndentation:
37
+ EnforcedStyle: case
54
38
  SupportedStyles:
55
39
  - case
56
40
  - end
57
41
  IndentOneStep: true
58
42
 
59
- Style/PercentLiteralDelimiters:
60
- PreferredDelimiters:
61
- '%w': "[]"
62
- '%W': "[]"
63
-
64
- Style/AccessModifierIndentation:
43
+ Layout/AccessModifierIndentation:
65
44
  EnforcedStyle: outdent
66
45
 
67
- Style/SignalException:
68
- Enabled: false
69
-
70
- Style/IndentationWidth:
71
- Enabled: false
46
+ Layout/EndAlignment:
47
+ EnforcedStyleAlignWith: variable
72
48
 
73
- Style/TrivialAccessors:
74
- ExactNameMatch: true
49
+ Style/FrozenStringLiteralComment:
50
+ Enabled: true
75
51
 
76
- Lint/EndAlignment:
77
- AlignWith: variable
52
+ Style/PercentLiteralDelimiters:
53
+ PreferredDelimiters:
54
+ '%w': "[]"
55
+ '%W': "[]"
78
56
 
79
- Lint/DefEndAlignment:
80
- Enabled: false
57
+ Style/StringLiterals:
58
+ EnforcedStyle: double_quotes
81
59
 
82
- Lint/HandleExceptions:
83
- Enabled: false
60
+ Style/StringLiteralsInInterpolation:
61
+ EnforcedStyle: double_quotes
84
62
 
85
- Style/SpecialGlobalVars:
63
+ Style/StructInheritance:
86
64
  Enabled: false
87
65
 
88
- Style/TrivialAccessors:
66
+ Style/AndOr:
89
67
  Enabled: false
90
68
 
91
- Style/IndentHash:
69
+ Style/Not:
92
70
  Enabled: false
93
71
 
94
72
  Style/DoubleNegation:
95
73
  Enabled: false
74
+
75
+ Documentation:
76
+ Enabled: false # TODO: Enable again once we have more docs
data/.travis.yml CHANGED
@@ -1,11 +1,21 @@
1
1
  language: ruby
2
- sudo: false
3
- rvm:
4
- - 2.0.0
5
- - 2.1
6
- - 2.2
7
- - jruby-19mode
8
- - rbx-2
9
- env:
10
- - RSPEC_VERSION="<2.99"
11
- - RSPEC_VERSION="~>3.0
2
+ before_install:
3
+ - gem install bundler -v 1.17.3
4
+
5
+ matrix:
6
+ include:
7
+ - rvm: 2.5.1 # Pre-installed Ruby version
8
+ script: bundle exec rake rubocop # ONLY lint once, first
9
+ - rvm: 2.1
10
+ - rvm: 2.2
11
+ - rvm: 2.3.5
12
+ - rvm: 2.4.6
13
+ - rvm: 2.5.5
14
+ - rvm: 2.6.3
15
+ - rvm: jruby-9.1.8.0
16
+ env:
17
+ - JRUBY_OPTS="--debug"
18
+ jdk: openjdk8
19
+ - rvm: jruby-9.2.8.0
20
+ env:
21
+ - JRUBY_OPTS="--debug"
data/CHANGELOG.md CHANGED
@@ -1,5 +1,47 @@
1
1
  # Pundit
2
2
 
3
+ ### Fixed
4
+
5
+ - Avoid name clashes with the Error class. (#590)
6
+
7
+ ### Changed
8
+
9
+ - Return a safer default NotAuthorizedError message. (#583)
10
+
11
+ ## 2.0.1 (2019-01-18)
12
+
13
+ ### Breaking changes
14
+
15
+ None
16
+
17
+ ### Other changes
18
+
19
+ - Improve exception handling for `#policy_scope` and `#policy_scope!`. (#550)
20
+ - Add `:policy` metadata to RSpec template. (#566)
21
+
22
+ ## 2.0.0 (2018-07-21)
23
+
24
+ No changes since beta1
25
+
26
+ ## 2.0.0.beta1 (2018-07-04)
27
+
28
+ ### Breaking changes
29
+
30
+ - Only pass last element of "namespace array" to policy and scope. (#529)
31
+ - Raise `InvalidConstructorError` if a policy or policy scope with an invalid constructor is called. (#462)
32
+ - Return passed object from `#authorize` method to make chaining possible. (#385)
33
+
34
+ ### Other changes
35
+
36
+ - Add `policy_class` option to `authorize` to be able to override the policy. (#441)
37
+ - Add `policy_scope_class` option to `authorize` to be able to override the policy scope. (#441)
38
+ - Fix `param_key` issue when passed an array. (#529)
39
+ - Allow specification of a `NilClassPolicy`. (#525)
40
+ - Make sure `policy_class` override is called when passed an array. (#475)
41
+
42
+ - Use `action_name` instead of `params[:action]`. (#419)
43
+ - Add `pundit_params_for` method to make it easy to customize params fetching. (#502)
44
+
3
45
  ## 1.1.0 (2016-01-14)
4
46
 
5
47
  - Can retrieve policies via an array of symbols/objects.
data/Gemfile CHANGED
@@ -1,4 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source "https://rubygems.org"
2
4
 
3
- gem "rspec", ENV["RSPEC_VERSION"] unless ENV["RSPEC_VERSION"].to_s.empty?
5
+ ruby RUBY_VERSION
6
+
4
7
  gemspec
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2012 Jonas Nicklas, Elabs AB
1
+ Copyright (c) 2019 Jonas Nicklas, Varvet AB
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Pundit
2
2
 
3
- [![Build Status](https://secure.travis-ci.org/elabs/pundit.svg?branch=master)](https://travis-ci.org/elabs/pundit)
4
- [![Code Climate](https://codeclimate.com/github/elabs/pundit.svg)](https://codeclimate.com/github/elabs/pundit)
5
- [![Inline docs](http://inch-ci.org/github/elabs/pundit.svg?branch=master)](http://inch-ci.org/github/elabs/pundit)
3
+ [![Build Status](https://secure.travis-ci.org/varvet/pundit.svg?branch=master)](https://travis-ci.org/varvet/pundit)
4
+ [![Code Climate](https://codeclimate.com/github/varvet/pundit.svg)](https://codeclimate.com/github/varvet/pundit)
5
+ [![Inline docs](http://inch-ci.org/github/varvet/pundit.svg?branch=master)](http://inch-ci.org/github/varvet/pundit)
6
6
  [![Gem Version](https://badge.fury.io/rb/pundit.svg)](http://badge.fury.io/rb/pundit)
7
7
 
8
8
  Pundit provides a set of helpers which guide you in leveraging regular Ruby
@@ -12,13 +12,13 @@ scaleable authorization system.
12
12
  Links:
13
13
 
14
14
  - [API documentation](http://www.rubydoc.info/gems/pundit)
15
- - [Source Code](https://github.com/elabs/pundit)
16
- - [Contributing](https://github.com/elabs/pundit/blob/master/CONTRIBUTING.md)
17
- - [Code of Conduct](https://github.com/elabs/pundit/blob/master/CODE_OF_CONDUCT.md)
15
+ - [Source Code](https://github.com/varvet/pundit)
16
+ - [Contributing](https://github.com/varvet/pundit/blob/master/CONTRIBUTING.md)
17
+ - [Code of Conduct](https://github.com/varvet/pundit/blob/master/CODE_OF_CONDUCT.md)
18
18
 
19
19
  Sponsored by:
20
20
 
21
- [<img src="http://d3cv91luii1z1d.cloudfront.net/logo-gh.png" alt="Elabs" height="50px"/>](http://elabs.se)
21
+ [<img src="https://www.varvet.com/images/wordmark-red.svg" alt="Varvet" height="50px"/>](https://www.varvet.com)
22
22
 
23
23
  ## Installation
24
24
 
@@ -116,7 +116,9 @@ and the given record. It then infers from the action name, that it should call
116
116
  `authorize` would have done something like this:
117
117
 
118
118
  ``` ruby
119
- raise "not authorized" unless PostPolicy.new(current_user, @post).update?
119
+ unless PostPolicy.new(current_user, @post).update?
120
+ raise Pundit::NotAuthorizedError, "not allowed to update? this #{@post.inspect}"
121
+ end
120
122
  ```
121
123
 
122
124
  You can pass a second argument to `authorize` if the name of the permission you
@@ -131,6 +133,18 @@ def publish
131
133
  end
132
134
  ```
133
135
 
136
+ You can pass an argument to override the policy class if necessary. For example:
137
+
138
+ ```ruby
139
+ def create
140
+ @publication = find_publication # assume this method returns any model that behaves like a publication
141
+ # @publication.class => Post
142
+ authorize @publication, policy_class: PublicationPolicy
143
+ @publication.publish!
144
+ redirect_to @publication
145
+ end
146
+ ```
147
+
134
148
  If you don't have an instance for the first argument to `authorize`, then you can pass
135
149
  the class. For example:
136
150
 
@@ -151,6 +165,15 @@ def admin_list
151
165
  end
152
166
  ```
153
167
 
168
+ `authorize` returns the object passed to it, so you can chain it like this:
169
+
170
+ Controller:
171
+ ```ruby
172
+ def show
173
+ @user = authorize User.find(params[:id])
174
+ end
175
+ ```
176
+
154
177
  You can easily get a hold of an instance of the policy through the `policy`
155
178
  method in both the view and controller. This is especially useful for
156
179
  conditionally showing links or buttons in the view:
@@ -172,6 +195,10 @@ class DashboardPolicy < Struct.new(:user, :dashboard)
172
195
  end
173
196
  ```
174
197
 
198
+ Note that the headless policy still needs to accept two arguments. The
199
+ second argument will just be the symbol `:dashboard` in this case which
200
+ is what is passed as the record to `authorize` below.
201
+
175
202
  ```ruby
176
203
  # In controllers
177
204
  authorize :dashboard, :show?
@@ -184,54 +211,6 @@ authorize :dashboard, :show?
184
211
  <% end %>
185
212
  ```
186
213
 
187
- ## Ensuring policies are used
188
-
189
- Pundit adds a method called `verify_authorized` to your controllers. This
190
- method will raise an exception if `authorize` has not yet been called. You
191
- should run this method in an `after_action` to ensure that you haven't
192
- forgotten to authorize the action. For example:
193
-
194
- ``` ruby
195
- class ApplicationController < ActionController::Base
196
- after_action :verify_authorized
197
- end
198
- ```
199
-
200
- Likewise, Pundit also adds `verify_policy_scoped` to your controller. This
201
- will raise an exception in the vein of `verify_authorized`. However, it tracks
202
- if `policy_scope` is used instead of `authorize`. This is mostly useful for
203
- controller actions like `index` which find collections with a scope and don't
204
- authorize individual instances.
205
-
206
- ``` ruby
207
- class ApplicationController < ActionController::Base
208
- after_action :verify_authorized, except: :index
209
- after_action :verify_policy_scoped, only: :index
210
- end
211
- ```
212
-
213
- If you're using `verify_authorized` in your controllers but need to
214
- conditionally bypass verification, you can use `skip_authorization`. For
215
- bypassing `verify_policy_scoped`, use `skip_policy_scope`. These are useful
216
- in circumstances where you don't want to disable verification for the
217
- entire action, but have some cases where you intend to not authorize.
218
-
219
- ```ruby
220
- def show
221
- record = Record.find_by(attribute: "value")
222
- if record.present?
223
- authorize record
224
- else
225
- skip_authorization
226
- end
227
- end
228
- ```
229
-
230
- If you need to perform some more sophisticated logic or you want to raise a custom
231
- exception you can use the two lower level methods `pundit_policy_authorized?`
232
- and `pundit_policy_scoped?` which return `true` or `false` depending on whether
233
- `authorize` or `policy_scope` have been called, respectively.
234
-
235
214
  ## Scopes
236
215
 
237
216
  Often, you will want to have some kind of view listing records which a
@@ -258,7 +237,7 @@ class PostPolicy < ApplicationPolicy
258
237
  end
259
238
 
260
239
  def update?
261
- user.admin? or not post.published?
240
+ user.admin? or not record.published?
262
241
  end
263
242
  end
264
243
  ```
@@ -291,7 +270,7 @@ class PostPolicy < ApplicationPolicy
291
270
  end
292
271
 
293
272
  def update?
294
- user.admin? or not post.published?
273
+ user.admin? or not record.published?
295
274
  end
296
275
  end
297
276
  ```
@@ -302,6 +281,19 @@ You can now use this class from your controller via the `policy_scope` method:
302
281
  def index
303
282
  @posts = policy_scope(Post)
304
283
  end
284
+
285
+ def show
286
+ @post = policy_scope(Post).find(params[:id])
287
+ end
288
+ ```
289
+
290
+ Like with the authorize method, you can also override the policy scope class:
291
+
292
+ ``` ruby
293
+ def index
294
+ # publication_class => Post
295
+ @publications = policy_scope(publication_class, policy_scope_class: PublicationPolicy::Scope)
296
+ end
305
297
  ```
306
298
 
307
299
  Just as with your policy, this will automatically infer that you want to use
@@ -322,6 +314,70 @@ You can, and are encouraged to, use this method in views:
322
314
  <% end %>
323
315
  ```
324
316
 
317
+ ## Ensuring policies and scopes are used
318
+
319
+ When you are developing an application with Pundit it can be easy to forget to
320
+ authorize some action. People are forgetful after all. Since Pundit encourages
321
+ you to add the `authorize` call manually to each controller action, it's really
322
+ easy to miss one.
323
+
324
+ Thankfully, Pundit has a handy feature which reminds you in case you forget.
325
+ Pundit tracks whether you have called `authorize` anywhere in your controller
326
+ action. Pundit also adds a method to your controllers called
327
+ `verify_authorized`. This method will raise an exception if `authorize` has not
328
+ yet been called. You should run this method in an `after_action` hook to ensure
329
+ that you haven't forgotten to authorize the action. For example:
330
+
331
+ ``` ruby
332
+ class ApplicationController < ActionController::Base
333
+ include Pundit
334
+ after_action :verify_authorized
335
+ end
336
+ ```
337
+
338
+ Likewise, Pundit also adds `verify_policy_scoped` to your controller. This
339
+ will raise an exception similar to `verify_authorized`. However, it tracks
340
+ if `policy_scope` is used instead of `authorize`. This is mostly useful for
341
+ controller actions like `index` which find collections with a scope and don't
342
+ authorize individual instances.
343
+
344
+ ``` ruby
345
+ class ApplicationController < ActionController::Base
346
+ include Pundit
347
+ after_action :verify_authorized, except: :index
348
+ after_action :verify_policy_scoped, only: :index
349
+ end
350
+ ```
351
+
352
+ **This verification mechanism only exists to aid you while developing your
353
+ application, so you don't forget to call `authorize`. It is not some kind of
354
+ failsafe mechanism or authorization mechanism. You should be able to remove
355
+ these filters without affecting how your app works in any way.**
356
+
357
+ Some people have found this feature confusing, while many others
358
+ find it extremely helpful. If you fall into the category of people who find it
359
+ confusing then you do not need to use it. Pundit will work just fine without
360
+ using `verify_authorized` and `verify_policy_scoped`.
361
+
362
+ ### Conditional verification
363
+
364
+ If you're using `verify_authorized` in your controllers but need to
365
+ conditionally bypass verification, you can use `skip_authorization`. For
366
+ bypassing `verify_policy_scoped`, use `skip_policy_scope`. These are useful
367
+ in circumstances where you don't want to disable verification for the
368
+ entire action, but have some cases where you intend to not authorize.
369
+
370
+ ```ruby
371
+ def show
372
+ record = Record.find_by(attribute: "value")
373
+ if record.present?
374
+ authorize record
375
+ else
376
+ skip_authorization
377
+ end
378
+ end
379
+ ```
380
+
325
381
  ## Manually specifying policy classes
326
382
 
327
383
  Sometimes you might want to explicitly declare which policy to use for a given
@@ -362,7 +418,8 @@ rails g pundit:policy post
362
418
 
363
419
  In many applications, only logged in users are really able to do anything. If
364
420
  you're building such a system, it can be kind of cumbersome to check that the
365
- user in a policy isn't `nil` for every single permission.
421
+ user in a policy isn't `nil` for every single permission. Aside from policies,
422
+ you can add this check to the base class for scopes.
366
423
 
367
424
  We suggest that you define a filter that redirects unauthenticated users to the
368
425
  login page. As a secondary defence, if you've defined an ApplicationPolicy, it
@@ -376,6 +433,37 @@ class ApplicationPolicy
376
433
  @user = user
377
434
  @record = record
378
435
  end
436
+
437
+ class Scope
438
+ attr_reader :user, :scope
439
+
440
+ def initialize(user, scope)
441
+ raise Pundit::NotAuthorizedError, "must be logged in" unless user
442
+ @user = user
443
+ @scope = scope
444
+ end
445
+ end
446
+ end
447
+ ```
448
+
449
+ ## NilClassPolicy
450
+
451
+ To support a [null object pattern](https://en.wikipedia.org/wiki/Null_Object_pattern)
452
+ you may find that you want to implement a `NilClassPolicy`. This might be useful
453
+ where you want to extend your ApplicationPolicy to allow some tolerance of, for
454
+ example, associations which might be `nil`.
455
+
456
+ ```ruby
457
+ class NilClassPolicy < ApplicationPolicy
458
+ class Scope < Scope
459
+ def resolve
460
+ raise Pundit::NotDefinedError, "Cannot scope NilClass"
461
+ end
462
+ end
463
+
464
+ def show?
465
+ false # Nobody can see nothing
466
+ end
379
467
  end
380
468
  ```
381
469
 
@@ -402,6 +490,10 @@ class ApplicationController < ActionController::Base
402
490
  end
403
491
  ```
404
492
 
493
+ Alternatively, you can globally handle Pundit::NotAuthorizedError's by having rails handle them as a 403 error and serving a 403 error page. Add the following to application.rb:
494
+
495
+ ```config.action_dispatch.rescue_responses["Pundit::NotAuthorizedError"] = :forbidden```
496
+
405
497
  ## Creating custom error messages
406
498
 
407
499
  `NotAuthorizedError`s provide information on what query (e.g. `:create?`), what
@@ -469,6 +561,48 @@ def pundit_user
469
561
  end
470
562
  ```
471
563
 
564
+ ## Policy Namespacing
565
+ In some cases it might be helpful to have multiple policies that serve different contexts for a
566
+ resource. A prime example of this is the case where User policies differ from Admin policies. To
567
+ authorize with a namespaced policy, pass the namespace into the `authorize` helper in an array:
568
+
569
+ ```ruby
570
+ authorize(post) # => will look for a PostPolicy
571
+ authorize([:admin, post]) # => will look for an Admin::PostPolicy
572
+ authorize([:foo, :bar, post]) # => will look for a Foo::Bar::PostPolicy
573
+
574
+ policy_scope(Post) # => will look for a PostPolicy::Scope
575
+ policy_scope([:admin, Post]) # => will look for an Admin::PostPolicy::Scope
576
+ policy_scope([:foo, :bar, Post]) # => will look for a Foo::Bar::PostPolicy::Scope
577
+ ```
578
+
579
+ If you are using namespaced policies for something like Admin views, it can be useful to
580
+ override the `policy_scope` and `authorize` helpers in your `AdminController` to automatically
581
+ apply the namespacing:
582
+
583
+ ```ruby
584
+ class AdminController < ApplicationController
585
+ def policy_scope(scope)
586
+ super([:admin, scope])
587
+ end
588
+
589
+ def authorize(record, query = nil)
590
+ super([:admin, record], query)
591
+ end
592
+ end
593
+
594
+ class Admin::PostController < AdminController
595
+ def index
596
+ policy_scope(Post)
597
+ end
598
+
599
+ def show
600
+ post = Post.find(params[:id])
601
+ authorize(post)
602
+ end
603
+ end
604
+ ```
605
+
472
606
  ## Additional context
473
607
 
474
608
  Pundit strongly encourages you to model your application in such a way that the
@@ -564,6 +698,45 @@ class PostsController < ApplicationController
564
698
  end
565
699
  ```
566
700
 
701
+ If you want to permit different attributes based on the current action, you can define a `permitted_attributes_for_#{action}` method on your policy:
702
+
703
+ ```ruby
704
+ # app/policies/post_policy.rb
705
+ class PostPolicy < ApplicationPolicy
706
+ def permitted_attributes_for_create
707
+ [:title, :body]
708
+ end
709
+
710
+ def permitted_attributes_for_edit
711
+ [:body]
712
+ end
713
+ end
714
+ ```
715
+
716
+ If you have defined an action-specific method on your policy for the current action, the `permitted_attributes` helper will call it instead of calling `permitted_attributes` on your controller.
717
+
718
+ If you need to fetch parameters based on namespaces different from the suggested one, override the below method, in your controller, and return an instance of `ActionController::Parameters`.
719
+
720
+ ```ruby
721
+ def pundit_params_for(record)
722
+ params.require(PolicyFinder.new(record).param_key)
723
+ end
724
+ ```
725
+
726
+ For example:
727
+
728
+ ```ruby
729
+ # If you don't want to use require
730
+ def pundit_params_for(record)
731
+ params.fetch(PolicyFinder.new(record).param_key, {})
732
+ end
733
+
734
+ # If you are using something like the JSON API spec
735
+ def pundit_params_for(_record)
736
+ params.fetch(:data, {}).fetch(:attributes, {})
737
+ end
738
+ ```
739
+
567
740
  ## RSpec
568
741
 
569
742
  ### Policy Specs
@@ -600,14 +773,22 @@ end
600
773
  An alternative approach to Pundit policy specs is scoping them to a user context as outlined in this
601
774
  [excellent post](http://thunderboltlabs.com/blog/2013/03/27/testing-pundit-policies-with-rspec/) and implemented in the third party [pundit-matchers](https://github.com/chrisalley/pundit-matchers) gem.
602
775
 
776
+ ### Scope Specs
777
+
778
+ Pundit does not provide a DSL for testing scopes. Just test it like a regular Ruby class!
779
+
603
780
  # External Resources
604
781
 
605
782
  - [RailsApps Example Application: Pundit and Devise](https://github.com/RailsApps/rails-devise-pundit)
606
783
  - [Migrating to Pundit from CanCan](http://blog.carbonfive.com/2013/10/21/migrating-to-pundit-from-cancan/)
607
784
  - [Testing Pundit Policies with RSpec](http://thunderboltlabs.com/blog/2013/03/27/testing-pundit-policies-with-rspec/)
608
- - [Using Pundit outside of a Rails controller](https://github.com/elabs/pundit/pull/136)
785
+ - [Using Pundit outside of a Rails controller](https://github.com/varvet/pundit/pull/136)
609
786
  - [Straightforward Rails Authorization with Pundit](http://www.sitepoint.com/straightforward-rails-authorization-with-pundit/)
610
787
 
788
+ ## Other implementations
789
+
790
+ - [Flask-Pundit](https://github.com/anurag90x/flask-pundit) (Python) is a [Flask](http://flask.pocoo.org/) extension "heavily inspired by" Pundit
791
+
611
792
  # License
612
793
 
613
794
  Licensed under the MIT license, see the separate LICENSE.txt file.