pundit 2.2.0 → 2.5.2

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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +98 -29
  3. data/CONTRIBUTING.md +3 -5
  4. data/README.md +125 -54
  5. data/SECURITY.md +19 -0
  6. data/config/rubocop-rspec.yml +5 -0
  7. data/lib/generators/pundit/install/install_generator.rb +3 -1
  8. data/lib/generators/pundit/install/templates/{application_policy.rb → application_policy.rb.tt} +1 -1
  9. data/lib/generators/pundit/policy/policy_generator.rb +3 -1
  10. data/lib/generators/pundit/policy/templates/policy.rb.tt +16 -0
  11. data/lib/generators/rspec/policy_generator.rb +4 -1
  12. data/lib/generators/rspec/templates/{policy_spec.rb → policy_spec.rb.tt} +1 -1
  13. data/lib/generators/test_unit/policy_generator.rb +4 -1
  14. data/lib/pundit/authorization.rb +176 -75
  15. data/lib/pundit/cache_store/legacy_store.rb +27 -0
  16. data/lib/pundit/cache_store/null_store.rb +30 -0
  17. data/lib/pundit/cache_store.rb +24 -0
  18. data/lib/pundit/context.rb +190 -0
  19. data/lib/pundit/error.rb +71 -0
  20. data/lib/pundit/helper.rb +16 -0
  21. data/lib/pundit/policy_finder.rb +34 -2
  22. data/lib/pundit/railtie.rb +20 -0
  23. data/lib/pundit/rspec.rb +92 -7
  24. data/lib/pundit/version.rb +2 -1
  25. data/lib/pundit.rb +45 -140
  26. metadata +25 -170
  27. data/.gitignore +0 -19
  28. data/.rubocop.yml +0 -72
  29. data/.travis.yml +0 -26
  30. data/.yardopts +0 -1
  31. data/CODE_OF_CONDUCT.md +0 -28
  32. data/Gemfile +0 -7
  33. data/Rakefile +0 -20
  34. data/lib/generators/pundit/policy/templates/policy.rb +0 -10
  35. data/pundit.gemspec +0 -33
  36. data/spec/authorization_spec.rb +0 -258
  37. data/spec/generators_spec.rb +0 -43
  38. data/spec/policies/post_policy_spec.rb +0 -22
  39. data/spec/policy_finder_spec.rb +0 -187
  40. data/spec/pundit_spec.rb +0 -427
  41. data/spec/spec_helper.rb +0 -275
  42. /data/lib/generators/test_unit/templates/{policy_test.rb → policy_test.rb.tt} +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 82606dec60dec4ddb9086a4d1a71447bda39f9f17fd5e38025937f0fdb7b9b1a
4
- data.tar.gz: e154a0dadc701871c49687ff843117e590011362be4cf3dfa7bc63ea4e5e698b
3
+ metadata.gz: eb37a66715ec9d8c397d11d11429d137673a43317335cd8e255a0b11f92d98ab
4
+ data.tar.gz: 82c44fa243f3dcc18f006dbbb87bb48754dfcae8baf1876a7a8266567dfe8ebe
5
5
  SHA512:
6
- metadata.gz: 0414e7e35eb8e2aa3bac79a75f2d8ae4e45f5cf4152150be239664f620560732990b3547aeac678b50e4b62036ab25c45170f12ca1897c6bf41938589e5ef0bd
7
- data.tar.gz: 964d660d1f79b36b8ace58452ca0adfef4f5ea68a7436f6373ae248f33cda7f017db5d5c5fbd0efca26fb5ee88a507cf900edc8bd0d7dad89a676cb308bd7bd1
6
+ metadata.gz: e650dddbc49cc94209dfdc22b12b5fedec499a07e0266c54c5bf8e93cc6573cdcd7cde045cc10e9e7343cb4de788c1459517b3b89333c2222700e821b624dc54
7
+ data.tar.gz: 443e7fefff8e69fd85aca350f174fa996f4c6fa7d524f17cd60cabec5ec09562bfccc25b25402d811934111b615542d9f470f899cd239cad7508d01471db16b6
data/CHANGELOG.md CHANGED
@@ -1,5 +1,74 @@
1
1
  # Pundit
2
2
 
3
+ ## Unreleased
4
+
5
+ ## 2.5.2 (2025-09-24)
6
+
7
+ ### Fixed
8
+ - Added `config/rubocop-rspec.yml` back from accidentally being excluded [#866](https://github.com/varvet/pundit/issues/866)
9
+
10
+ ## 2.5.1 (2025-09-12)
11
+
12
+ ### Fixed
13
+ - Requiring only `pundit/rspec` no longer raises an error in Active Support [#857](https://github.com/varvet/pundit/issues/857)
14
+
15
+ ## 2.5.0 (2025-03-03)
16
+
17
+ ### Added
18
+
19
+ - Add `Pundit::Authorization#pundit_reset!` hook to reset the policy and policy scope cache. [#830](https://github.com/varvet/pundit/issues/830)
20
+ - Add links to gemspec. [#845](https://github.com/varvet/pundit/issues/845)
21
+ - Register policies directories for Rails 8 code statistics [#833](https://github.com/varvet/pundit/issues/833)
22
+ - Added an example for how to use pundit with Rails 8 authentication generator [#850](https://github.com/varvet/pundit/issues/850)
23
+
24
+ ### Changed
25
+
26
+ - Deprecated `Pundit::SUFFIX`, moved it to `Pundit::PolicyFinder::SUFFIX` [#835](https://github.com/varvet/pundit/issues/835)
27
+ - Explicitly require less of `active_support` [#837](https://github.com/varvet/pundit/issues/837)
28
+ - Using `permit` matcher without a surrouding `permissions` block now raises a useful error. [#836](https://github.com/varvet/pundit/issues/836)
29
+
30
+ ### Fixed
31
+
32
+ - Using a hash as custom cache in `Pundit.authorize` now works as documented. [#838](https://github.com/varvet/pundit/issues/838)
33
+
34
+ ## 2.4.0 (2024-08-26)
35
+
36
+ ### Changed
37
+
38
+ - Improve the `NotAuthorizedError` message to include the policy class.
39
+ Furthermore, in the case where the record passed is a class instead of an instance, the class name is given. [#812](https://github.com/varvet/pundit/issues/812)
40
+
41
+ ### Added
42
+
43
+ - Add customizable permit matcher description [#806](https://github.com/varvet/pundit/issues/806)
44
+ - Add support for filter_run_when_matching :focus with permissions helper. [#820](https://github.com/varvet/pundit/issues/820)
45
+
46
+ ## 2.3.2 (2024-05-08)
47
+
48
+ - Refactor: First pass of Pundit::Context [#797](https://github.com/varvet/pundit/issues/797)
49
+
50
+ ### Changed
51
+
52
+ - Update `ApplicationPolicy` generator to qualify the `Scope` class name [#792](https://github.com/varvet/pundit/issues/792)
53
+ - Policy generator uses `NoMethodError` to indicate `#resolve` is not implemented [#776](https://github.com/varvet/pundit/issues/776)
54
+
55
+ ## Deprecated
56
+
57
+ - Dropped support for Ruby 3.0 [#796](https://github.com/varvet/pundit/issues/796)
58
+
59
+ ## 2.3.1 (2023-07-17)
60
+
61
+ ### Fixed
62
+
63
+ - Use `Kernel.warn` instead of `ActiveSupport::Deprecation.warn` for deprecations [#764](https://github.com/varvet/pundit/issues/764)
64
+ - Policy generator now works on Ruby 3.2 [#754](https://github.com/varvet/pundit/issues/754)
65
+
66
+ ## 2.3.0 (2022-12-19)
67
+
68
+ ### Added
69
+
70
+ - add support for rubocop-rspec syntax extensions [#745](https://github.com/varvet/pundit/issues/745)
71
+
3
72
  ## 2.2.0 (2022-02-11)
4
73
 
5
74
  ### Fixed
@@ -12,41 +81,41 @@
12
81
 
13
82
  ### Deprecated
14
83
 
15
- - Deprecate `include Pundit` in favor of `include Pundit::Authorization` (#621)
84
+ - Deprecate `include Pundit` in favor of `include Pundit::Authorization` [#621](https://github.com/varvet/pundit/issues/621)
16
85
 
17
86
  ## 2.1.1 (2021-08-13)
18
87
 
19
88
  Friday 13th-release!
20
89
 
21
- Careful! The bugfix below (#626) could break existing code. If you rely on the
90
+ Careful! The bugfix below [#626](https://github.com/varvet/pundit/issues/626) could break existing code. If you rely on the
22
91
  return value for `authorize` and namespaced policies you might need to do some
23
92
  changes.
24
93
 
25
94
  ### Fixed
26
95
 
27
96
  - `.authorize` and `#authorize` return the instance, even for namespaced
28
- policies (#626)
97
+ policies [#626](https://github.com/varvet/pundit/issues/626)
29
98
 
30
99
  ### Changed
31
100
 
32
- - Generate application scope with `protected` attr_readers. (#616)
101
+ - Generate application scope with `protected` attr_readers. [#616](https://github.com/varvet/pundit/issues/616)
33
102
 
34
103
  ### Removed
35
104
 
36
- - Dropped support for Ruby end-of-life versions: 2.1 and 2.2. (#604)
37
- - Dropped support for Ruby end-of-life versions: 2.3 (#633)
38
- - Dropped support for Ruby end-of-life versions: 2.4, 2.5 and JRuby 9.1 (#676)
39
- - Dropped support for RSpec 2 (#615)
105
+ - Dropped support for Ruby end-of-life versions: 2.1 and 2.2. [#604](https://github.com/varvet/pundit/issues/604)
106
+ - Dropped support for Ruby end-of-life versions: 2.3 [#633](https://github.com/varvet/pundit/issues/633)
107
+ - Dropped support for Ruby end-of-life versions: 2.4, 2.5 and JRuby 9.1 [#676](https://github.com/varvet/pundit/issues/676)
108
+ - Dropped support for RSpec 2 [#615](https://github.com/varvet/pundit/issues/615)
40
109
 
41
110
  ## 2.1.0 (2019-08-14)
42
111
 
43
112
  ### Fixed
44
113
 
45
- - Avoid name clashes with the Error class. (#590)
114
+ - Avoid name clashes with the Error class. [#590](https://github.com/varvet/pundit/issues/590)
46
115
 
47
116
  ### Changed
48
117
 
49
- - Return a safer default NotAuthorizedError message. (#583)
118
+ - Return a safer default NotAuthorizedError message. [#583](https://github.com/varvet/pundit/issues/583)
50
119
 
51
120
  ## 2.0.1 (2019-01-18)
52
121
 
@@ -56,8 +125,8 @@ None
56
125
 
57
126
  ### Other changes
58
127
 
59
- - Improve exception handling for `#policy_scope` and `#policy_scope!`. (#550)
60
- - Add `:policy` metadata to RSpec template. (#566)
128
+ - Improve exception handling for `#policy_scope` and `#policy_scope!`. [#550](https://github.com/varvet/pundit/issues/550)
129
+ - Add `:policy` metadata to RSpec template. [#566](https://github.com/varvet/pundit/issues/566)
61
130
 
62
131
  ## 2.0.0 (2018-07-21)
63
132
 
@@ -67,20 +136,20 @@ No changes since beta1
67
136
 
68
137
  ### Breaking changes
69
138
 
70
- - Only pass last element of "namespace array" to policy and scope. (#529)
71
- - Raise `InvalidConstructorError` if a policy or policy scope with an invalid constructor is called. (#462)
72
- - Return passed object from `#authorize` method to make chaining possible. (#385)
139
+ - Only pass last element of "namespace array" to policy and scope. [#529](https://github.com/varvet/pundit/issues/529)
140
+ - Raise `InvalidConstructorError` if a policy or policy scope with an invalid constructor is called. [#462](https://github.com/varvet/pundit/issues/462)
141
+ - Return passed object from `#authorize` method to make chaining possible. [#385](https://github.com/varvet/pundit/issues/385)
73
142
 
74
143
  ### Other changes
75
144
 
76
- - Add `policy_class` option to `authorize` to be able to override the policy. (#441)
77
- - Add `policy_scope_class` option to `authorize` to be able to override the policy scope. (#441)
78
- - Fix `param_key` issue when passed an array. (#529)
79
- - Allow specification of a `NilClassPolicy`. (#525)
80
- - Make sure `policy_class` override is called when passed an array. (#475)
145
+ - Add `policy_class` option to `authorize` to be able to override the policy. [#441](https://github.com/varvet/pundit/issues/441)
146
+ - Add `policy_scope_class` option to `authorize` to be able to override the policy scope. [#441](https://github.com/varvet/pundit/issues/441)
147
+ - Fix `param_key` issue when passed an array. [#529](https://github.com/varvet/pundit/issues/529)
148
+ - Allow specification of a `NilClassPolicy`. [#525](https://github.com/varvet/pundit/issues/525)
149
+ - Make sure `policy_class` override is called when passed an array. [#475](https://github.com/varvet/pundit/issues/475)
81
150
 
82
- - Use `action_name` instead of `params[:action]`. (#419)
83
- - Add `pundit_params_for` method to make it easy to customize params fetching. (#502)
151
+ - Use `action_name` instead of `params[:action]`. [#419](https://github.com/varvet/pundit/issues/419)
152
+ - Add `pundit_params_for` method to make it easy to customize params fetching. [#502](https://github.com/varvet/pundit/issues/502)
84
153
 
85
154
  ## 1.1.0 (2016-01-14)
86
155
 
@@ -112,16 +181,16 @@ No changes since beta1
112
181
 
113
182
  ## 0.3.0 (2014-08-22)
114
183
 
115
- - Extend the default `ApplicationPolicy` with an `ApplicationPolicy::Scope` (#120)
116
- - Fix RSpec 3 deprecation warnings for built-in matchers (#162)
117
- - Generate blank policy spec/test files for Rspec/MiniTest/Test::Unit in Rails (#138)
184
+ - Extend the default `ApplicationPolicy` with an `ApplicationPolicy::Scope` [#120](https://github.com/varvet/pundit/issues/120)
185
+ - Fix RSpec 3 deprecation warnings for built-in matchers [#162](https://github.com/varvet/pundit/issues/162)
186
+ - Generate blank policy spec/test files for Rspec/MiniTest/Test::Unit in Rails [#138](https://github.com/varvet/pundit/issues/138)
118
187
 
119
188
  ## 0.2.3 (2014-04-06)
120
189
 
121
- - Customizable error messages: `#query`, `#record` and `#policy` methods on `Pundit::NotAuthorizedError` (#114)
122
- - Raise a different `Pundit::AuthorizationNotPerformedError` when `authorize` call is expected in controller action but missing (#109)
123
- - Update Rspec matchers for Rspec 3 (#124)
190
+ - Customizable error messages: `#query`, `#record` and `#policy` methods on `Pundit::NotAuthorizedError` [#114](https://github.com/varvet/pundit/issues/114)
191
+ - Raise a different `Pundit::AuthorizationNotPerformedError` when `authorize` call is expected in controller action but missing [#109](https://github.com/varvet/pundit/issues/109)
192
+ - Update Rspec matchers for Rspec 3 [#124](https://github.com/varvet/pundit/issues/124)
124
193
 
125
194
  ## 0.2.2 (2014-02-07)
126
195
 
127
- - Customize the user to be passed into policies: `pundit_user` (#42)
196
+ - Customize the user to be passed into policies: `pundit_user` [#42](https://github.com/varvet/pundit/issues/42)
data/CONTRIBUTING.md CHANGED
@@ -1,9 +1,6 @@
1
1
  ## Security issues
2
2
 
3
- If you have found a security related issue, please do not file an issue on
4
- GitHub or send a PR addressing the issue. Contact
5
- [Jonas](mailto:jonas.nicklas@gmail.com) directly. You will be given public
6
- credit for your disclosure.
3
+ If you have found a security related issue, please do not file an issue on GitHub or send a PR addressing the issue. Refer to [SECURITY.md](./SECURITY.md) for instructions.
7
4
 
8
5
  ## Reporting issues
9
6
 
@@ -23,7 +20,7 @@ Pundit version, OS version and any stack traces you have are very valuable.
23
20
  - **Document any change in behaviour**. Make sure the README and any other
24
21
  relevant documentation are kept up-to-date.
25
22
 
26
- - **Create topic branches**. Please don't ask us to pull from your master branch.
23
+ - **Create topic branches**. Please don't ask us to pull from your main branch.
27
24
 
28
25
  - **One pull request per feature**. If you want to do more than one thing, send
29
26
  multiple pull requests.
@@ -31,3 +28,4 @@ Pundit version, OS version and any stack traces you have are very valuable.
31
28
  - **Send coherent history**. Make sure each individual commit in your pull
32
29
  request is meaningful. If you had to make multiple intermediate commits while
33
30
  developing, please squash them before sending them to us.
31
+ - **Update the CHANGELOG.** Don't forget to add your new changes to the CHANGELOG.
data/README.md CHANGED
@@ -1,31 +1,29 @@
1
1
  # Pundit
2
2
 
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
- [![Gem Version](https://badge.fury.io/rb/pundit.svg)](http://badge.fury.io/rb/pundit)
3
+ [![Main](https://github.com/varvet/pundit/actions/workflows/main.yml/badge.svg)](https://github.com/varvet/pundit/actions/workflows/main.yml)
4
+ [![Maintainability](https://qlty.sh/gh/varvet/projects/pundit/maintainability.svg)](https://qlty.sh/gh/varvet/projects/pundit)
5
+ [![Inline docs](https://inch-ci.org/github/varvet/pundit.svg?branch=main)](https://inch-ci.org/github/varvet/pundit)
6
+ [![Gem Version](https://badge.fury.io/rb/pundit.svg)](https://badge.fury.io/rb/pundit)
7
7
 
8
8
  Pundit provides a set of helpers which guide you in leveraging regular Ruby
9
- classes and object oriented design patterns to build a simple, robust and
9
+ classes and object oriented design patterns to build a straightforward, robust, and
10
10
  scalable authorization system.
11
11
 
12
- Links:
12
+ ## Links:
13
13
 
14
- - [API documentation for the most recent version](http://www.rubydoc.info/gems/pundit)
14
+ - [API documentation for the most recent version](https://www.rubydoc.info/gems/pundit)
15
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)
16
+ - [Contributing](https://github.com/varvet/pundit/blob/main/CONTRIBUTING.md)
17
+ - [Code of Conduct](https://github.com/varvet/pundit/blob/main/CODE_OF_CONDUCT.md)
18
18
 
19
- Sponsored by:
20
-
21
- [<img src="https://www.varvet.com/images/wordmark-red.svg" alt="Varvet" height="50px"/>](https://www.varvet.com)
19
+ <strong>Sponsored by:</strong> <a href="https://www.varvet.com">Varvet<br><br><img src="https://github.com/varvet/pundit/assets/99166/aa9efa0a-6903-4037-abee-1824edc57f1a" alt="Varvet logo" height="120"></div>
22
20
 
23
21
  ## Installation
24
22
 
25
23
  > **Please note** that the README on GitHub is accurate with the _latest code on GitHub_. You are most likely using a released version of Pundit, so please refer to the [documentation for the latest released version of Pundit](https://www.rubydoc.info/gems/pundit).
26
24
 
27
- ``` ruby
28
- gem "pundit"
25
+ ``` sh
26
+ bundle add pundit
29
27
  ```
30
28
 
31
29
  Include `Pundit::Authorization` in your application controller:
@@ -49,8 +47,8 @@ can pick up any classes in the new `app/policies/` directory.
49
47
  ## Policies
50
48
 
51
49
  Pundit is focused around the notion of policy classes. We suggest that you put
52
- these classes in `app/policies`. This is a simple example that allows updating
53
- a post if the user is an admin, or if the post is unpublished:
50
+ these classes in `app/policies`. This is an example that allows updating a post
51
+ if the user is an admin, or if the post is unpublished:
54
52
 
55
53
  ``` ruby
56
54
  class PostPolicy
@@ -67,7 +65,7 @@ class PostPolicy
67
65
  end
68
66
  ```
69
67
 
70
- As you can see, this is just a plain Ruby class. Pundit makes the following
68
+ As you can see, this is a plain Ruby class. Pundit makes the following
71
69
  assumptions about this class:
72
70
 
73
71
  - The class has the same name as some kind of model class, only suffixed
@@ -118,7 +116,7 @@ and the given record. It then infers from the action name, that it should call
118
116
 
119
117
  ``` ruby
120
118
  unless PostPolicy.new(current_user, @post).update?
121
- raise Pundit::NotAuthorizedError, "not allowed to update? this #{@post.inspect}"
119
+ raise Pundit::NotAuthorizedError, "not allowed to PostPolicy#update? this Post"
122
120
  end
123
121
  ```
124
122
 
@@ -199,7 +197,7 @@ you can retrieve it by passing a symbol.
199
197
  class DashboardPolicy
200
198
  attr_reader :user
201
199
 
202
- # _record in this example will just be :dashboard
200
+ # `_record` in this example will be :dashboard
203
201
  def initialize(user, _record)
204
202
  @user = user
205
203
  end
@@ -211,7 +209,7 @@ end
211
209
  ```
212
210
 
213
211
  Note that the headless policy still needs to accept two arguments. The
214
- second argument will just be the symbol `:dashboard` in this case which
212
+ second argument will be the symbol `:dashboard` in this case, which
215
213
  is what is passed as the record to `authorize` below.
216
214
 
217
215
  ```ruby
@@ -279,7 +277,7 @@ generator, or create your own base class to inherit from:
279
277
 
280
278
  ``` ruby
281
279
  class PostPolicy < ApplicationPolicy
282
- class Scope < Scope
280
+ class Scope < ApplicationPolicy::Scope
283
281
  def resolve
284
282
  if user.admin?
285
283
  scope.all
@@ -362,8 +360,15 @@ authorize individual instances.
362
360
  ``` ruby
363
361
  class ApplicationController < ActionController::Base
364
362
  include Pundit::Authorization
365
- after_action :verify_authorized, except: :index
366
- after_action :verify_policy_scoped, only: :index
363
+ after_action :verify_pundit_authorization
364
+
365
+ def verify_pundit_authorization
366
+ if action_name == "index"
367
+ verify_policy_scoped
368
+ else
369
+ verify_authorized
370
+ end
371
+ end
367
372
  end
368
373
  ```
369
374
 
@@ -374,7 +379,7 @@ these filters without affecting how your app works in any way.**
374
379
 
375
380
  Some people have found this feature confusing, while many others
376
381
  find it extremely helpful. If you fall into the category of people who find it
377
- confusing then you do not need to use it. Pundit will work just fine without
382
+ confusing then you do not need to use it. Pundit will work fine without
378
383
  using `verify_authorized` and `verify_policy_scoped`.
379
384
 
380
385
  ### Conditional verification
@@ -419,20 +424,13 @@ class Post
419
424
  end
420
425
  ```
421
426
 
422
- ## Just plain old Ruby
427
+ ## Plain old Ruby
423
428
 
424
- As you can see, Pundit doesn't do anything you couldn't have easily done
425
- yourself. It's a very small library, it just provides a few neat helpers.
426
- Together these give you the power of building a well structured, fully working
427
- authorization system without using any special DSLs or funky syntax or
428
- anything.
429
+ Pundit is a very small library on purpose, and it doesn't do anything you can't do yourself. There's no secret sauce here. It does as little as possible, and then gets out of your way.
429
430
 
430
- Remember that all of the policy and scope classes are just plain Ruby classes,
431
- which means you can use the same mechanisms you always use to DRY things up.
432
- Encapsulate a set of permissions into a module and include them in multiple
433
- policies. Use `alias_method` to make some permissions behave the same as
434
- others. Inherit from a base set of permissions. Use metaprogramming if you
435
- really have to.
431
+ With the few but powerful helpers available in Pundit, you have the power to build a well structured, fully working authorization system without using any special DSLs or funky syntax.
432
+
433
+ Remember that all of the policy and scope classes are plain Ruby classes, which means you can use the same mechanisms you always use to DRY things up. Encapsulate a set of permissions into a module and include them in multiple policies. Use `alias_method` to make some permissions behave the same as others. Inherit from a base set of permissions. Use metaprogramming if you really have to.
436
434
 
437
435
  ## Generator
438
436
 
@@ -483,7 +481,7 @@ example, associations which might be `nil`.
483
481
 
484
482
  ```ruby
485
483
  class NilClassPolicy < ApplicationPolicy
486
- class Scope < Scope
484
+ class Scope < ApplicationPolicy::Scope
487
485
  def resolve
488
486
  raise Pundit::NotDefinedError, "Cannot scope NilClass"
489
487
  end
@@ -498,7 +496,7 @@ end
498
496
  ## Rescuing a denied Authorization in Rails
499
497
 
500
498
  Pundit raises a `Pundit::NotAuthorizedError` you can
501
- [rescue_from](http://guides.rubyonrails.org/action_controller_overview.html#rescue-from)
499
+ [rescue_from](https://guides.rubyonrails.org/action_controller_overview.html#rescue-from)
502
500
  in your `ApplicationController`. You can customize the `user_not_authorized`
503
501
  method in every controller.
504
502
 
@@ -512,7 +510,7 @@ class ApplicationController < ActionController::Base
512
510
 
513
511
  def user_not_authorized
514
512
  flash[:alert] = "You are not authorized to perform this action."
515
- redirect_to(request.referrer || root_path)
513
+ redirect_back_or_to(root_path)
516
514
  end
517
515
  end
518
516
  ```
@@ -541,7 +539,7 @@ class ApplicationController < ActionController::Base
541
539
  policy_name = exception.policy.class.to_s.underscore
542
540
 
543
541
  flash[:error] = t "#{policy_name}.#{exception.query}", scope: "pundit", default: :default
544
- redirect_to(request.referrer || root_path)
542
+ redirect_back_or_to(root_path)
545
543
  end
546
544
  end
547
545
  ```
@@ -555,8 +553,7 @@ en:
555
553
  create?: 'You cannot create posts!'
556
554
  ```
557
555
 
558
- Of course, this is just an example. Pundit is agnostic as to how you implement
559
- your error messaging.
556
+ This is an example. Pundit is agnostic as to how you implement your error messaging.
560
557
 
561
558
  ## Manually retrieving policies and scopes
562
559
 
@@ -578,9 +575,7 @@ those without the bang will return nil.
578
575
 
579
576
  ## Customize Pundit user
580
577
 
581
- In some cases your controller might not have access to `current_user`, or your
582
- `current_user` is not the method that should be invoked by Pundit. Simply
583
- define a method in your controller called `pundit_user`.
578
+ On occasion, your controller may be unable to access `current_user`, or the method that should be invoked by Pundit may not be `current_user`. To address this, you can define a method in your controller named `pundit_user`.
584
579
 
585
580
  ```ruby
586
581
  def pundit_user
@@ -588,6 +583,36 @@ def pundit_user
588
583
  end
589
584
  ```
590
585
 
586
+ For instance, Rails 8 includes a built-in [authentication generator](https://github.com/rails/rails/tree/8-0-stable/railties/lib/rails/generators/rails/authentication). If you choose to use it, the currently logged-in user is accessed via `Current.user` instead of `current_user`.
587
+
588
+ To ensure compatibility with Pundit, define a `pundit_user` method in `application_controller.rb` (or another suitable location) as follows:
589
+
590
+ ```ruby
591
+ def pundit_user
592
+ Current.user
593
+ end
594
+ ```
595
+
596
+ ### Handling User Switching in Pundit
597
+
598
+ When switching users in your application, it's important to reset the Pundit user context to ensure that authorization policies are applied correctly for the new user. Pundit caches the user context, so failing to reset it could result in incorrect permissions being applied.
599
+
600
+ To handle user switching, you can use the following pattern in your controller:
601
+
602
+ ```ruby
603
+ class ApplicationController
604
+ include Pundit::Authorization
605
+
606
+ def switch_user_to(user)
607
+ terminate_session if authenticated?
608
+ start_new_session_for user
609
+ pundit_reset!
610
+ end
611
+ end
612
+ ```
613
+
614
+ Make sure to invoke `pundit_reset!` whenever changing the user. This ensures the cached authorization context is reset, preventing any incorrect permissions from being applied.
615
+
591
616
  ## Policy Namespacing
592
617
  In some cases it might be helpful to have multiple policies that serve different contexts for a
593
618
  resource. A prime example of this is the case where User policies differ from Admin policies. To
@@ -692,7 +717,7 @@ You can now retrieve these attributes from the policy:
692
717
  class PostsController < ApplicationController
693
718
  def update
694
719
  @post = Post.find(params[:id])
695
- if @post.update_attributes(post_params)
720
+ if @post.update(post_params)
696
721
  redirect_to @post
697
722
  else
698
723
  render :edit
@@ -714,7 +739,7 @@ However, this is a bit cumbersome, so Pundit provides a convenient helper method
714
739
  class PostsController < ApplicationController
715
740
  def update
716
741
  @post = Post.find(params[:id])
717
- if @post.update_attributes(permitted_attributes(@post))
742
+ if @post.update(permitted_attributes(@post))
718
743
  redirect_to @post
719
744
  else
720
745
  render :edit
@@ -766,6 +791,10 @@ end
766
791
 
767
792
  ### Policy Specs
768
793
 
794
+ > [!TIP]
795
+ > An alternative approach to Pundit policy specs is scoping them to a user context as outlined in this
796
+ [excellent post](https://thunderboltlabs.com/blog/2013/03/27/testing-pundit-policies-with-rspec/) and implemented in the third party [pundit-matchers](https://github.com/punditcommunity/pundit-matchers) gem.
797
+
769
798
  Pundit includes a mini-DSL for writing expressive tests for your policies in RSpec.
770
799
  Require `pundit/rspec` in your `spec_helper.rb`:
771
800
 
@@ -795,25 +824,67 @@ describe PostPolicy do
795
824
  end
796
825
  ```
797
826
 
798
- An alternative approach to Pundit policy specs is scoping them to a user context as outlined in this
799
- [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.
827
+ ### Custom matcher description
828
+
829
+ By default rspec includes an inspected `user` and `record` in the matcher description, which might become overly verbose:
830
+
831
+ ```
832
+ PostPolicy
833
+ update? and show?
834
+ is expected to permit #<User:0x0000000104aefd80> and #<Post:0x0000000104aef8d0 @user=#<User:0x0000000104aefd80>>
835
+ ```
836
+
837
+ You can override the default description with a static string, or a block:
838
+
839
+ ```ruby
840
+ # static alternative: Pundit::RSpec::Matchers.description = "permit the user"
841
+ Pundit::RSpec::Matchers.description = ->(user, record) do
842
+ "permit user with role #{user.role} to access record with ID #{record.id}"
843
+ end
844
+ ```
845
+
846
+ Which would make for a less chatty output:
847
+
848
+ ```
849
+ PostPolicy
850
+ update? and show?
851
+ is expected to permit user with role admin to access record with ID 130
852
+ ```
853
+
854
+ ### Focus Support
855
+
856
+ If your RSpec config has `filter_run_when_matching :focus`, you may tag the `permissions` helper like so:
857
+
858
+ ```
859
+ permissions :show?, :focus do
860
+ ```
800
861
 
801
862
  ### Scope Specs
802
863
 
803
- Pundit does not provide a DSL for testing scopes. Just test it like a regular Ruby class!
864
+ Pundit does not provide a DSL for testing scopes. Test them like you would a regular Ruby class!
865
+
866
+ ### Linting with RuboCop RSpec
867
+
868
+ When you lint your RSpec spec files with `rubocop-rspec`, it will fail to properly detect RSpec constructs that Pundit defines, `permissions`.
869
+ Make sure to use `rubocop-rspec` 2.0 or newer and add the following to your `.rubocop.yml`:
870
+
871
+ ```yaml
872
+ inherit_gem:
873
+ pundit: config/rubocop-rspec.yml
874
+ ```
804
875
 
805
876
  # External Resources
806
877
 
807
878
  - [RailsApps Example Application: Pundit and Devise](https://github.com/RailsApps/rails-devise-pundit)
808
- - [Migrating to Pundit from CanCan](http://blog.carbonfive.com/2013/10/21/migrating-to-pundit-from-cancan/)
809
- - [Testing Pundit Policies with RSpec](http://thunderboltlabs.com/blog/2013/03/27/testing-pundit-policies-with-rspec/)
879
+ - [Migrating to Pundit from CanCan](https://blog.carbonfive.com/2013/10/21/migrating-to-pundit-from-cancan/)
880
+ - [Testing Pundit Policies with RSpec](https://thunderboltlabs.com/blog/2013/03/27/testing-pundit-policies-with-rspec/)
810
881
  - [Testing Pundit with Minitest](https://github.com/varvet/pundit/issues/204#issuecomment-60166450)
811
882
  - [Using Pundit outside of a Rails controller](https://github.com/varvet/pundit/pull/136)
812
- - [Straightforward Rails Authorization with Pundit](http://www.sitepoint.com/straightforward-rails-authorization-with-pundit/)
883
+ - [Straightforward Rails Authorization with Pundit](https://www.sitepoint.com/straightforward-rails-authorization-with-pundit/)
813
884
 
814
885
  ## Other implementations
815
886
 
816
- - [Flask-Pundit](https://github.com/anurag90x/flask-pundit) (Python) is a [Flask](http://flask.pocoo.org/) extension "heavily inspired by" Pundit
887
+ - [Flask-Pundit](https://github.com/anurag90x/flask-pundit) (Python) is a [Flask](https://flask.pocoo.org/) extension "heavily inspired by" Pundit
817
888
 
818
889
  # License
819
890
 
data/SECURITY.md ADDED
@@ -0,0 +1,19 @@
1
+ # Security Policy
2
+
3
+ Please do not file an issue on GitHub, or send a PR addressing the issue.
4
+
5
+ ## Supported versions
6
+
7
+ Most recent major version only.
8
+
9
+ ## Reporting a vulnerability
10
+
11
+ Contact one of the maintainers directly:
12
+
13
+ * [@Burgestrand](https://github.com/Burgestrand)
14
+ * [@dgmstuart](https://github.com/dgmstuart)
15
+ * [@varvet](https://github.com/varvet)
16
+
17
+ You can report vulnerabilities on GitHub too: https://github.com/varvet/pundit/security
18
+
19
+ Thank you!
@@ -0,0 +1,5 @@
1
+ RSpec:
2
+ Language:
3
+ ExampleGroups:
4
+ Regular:
5
+ - permissions
@@ -1,12 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Pundit
4
+ # @private
4
5
  module Generators
6
+ # @private
5
7
  class InstallGenerator < ::Rails::Generators::Base
6
8
  source_root File.expand_path("templates", __dir__)
7
9
 
8
10
  def copy_application_policy
9
- template "application_policy.rb", "app/policies/application_policy.rb"
11
+ template "application_policy.rb.tt", "app/policies/application_policy.rb"
10
12
  end
11
13
  end
12
14
  end
@@ -43,7 +43,7 @@ class ApplicationPolicy
43
43
  end
44
44
 
45
45
  def resolve
46
- raise NotImplementedError, "You must define #resolve in #{self.class}"
46
+ raise NoMethodError, "You must define #resolve in #{self.class}"
47
47
  end
48
48
 
49
49
  private
@@ -1,12 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Pundit
4
+ # @private
4
5
  module Generators
6
+ # @private
5
7
  class PolicyGenerator < ::Rails::Generators::NamedBase
6
8
  source_root File.expand_path("templates", __dir__)
7
9
 
8
10
  def create_policy
9
- template "policy.rb", File.join("app/policies", class_path, "#{file_name}_policy.rb")
11
+ template "policy.rb.tt", File.join("app/policies", class_path, "#{file_name}_policy.rb")
10
12
  end
11
13
 
12
14
  hook_for :test_framework
@@ -0,0 +1,16 @@
1
+ <% module_namespacing do -%>
2
+ class <%= class_name %>Policy < ApplicationPolicy
3
+ # NOTE: Up to Pundit v2.3.1, the inheritance was declared as
4
+ # `Scope < Scope` rather than `Scope < ApplicationPolicy::Scope`.
5
+ # In most cases the behavior will be identical, but if updating existing
6
+ # code, beware of possible changes to the ancestors:
7
+ # https://gist.github.com/Burgestrand/4b4bc22f31c8a95c425fc0e30d7ef1f5
8
+
9
+ class Scope < ApplicationPolicy::Scope
10
+ # NOTE: Be explicit about which records you allow access to!
11
+ # def resolve
12
+ # scope.all
13
+ # end
14
+ end
15
+ end
16
+ <% end -%>