pundit 1.1.0 → 2.1.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.
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.