pundit 2.2.0 → 2.4.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 +4 -4
- data/.github/ISSUE_TEMPLATE/bug_report.md +20 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +26 -0
- data/.github/PULL_REQUEST_TEMPLATE/gem_release_template.md +8 -0
- data/.github/pull_request_template.md +9 -0
- data/.github/workflows/main.yml +112 -0
- data/.github/workflows/push_gem.yml +33 -0
- data/.rubocop.yml +7 -16
- data/CHANGELOG.md +40 -0
- data/CODE_OF_CONDUCT.md +1 -1
- data/CONTRIBUTING.md +3 -5
- data/Gemfile +3 -2
- data/README.md +95 -54
- data/SECURITY.md +19 -0
- data/config/rubocop-rspec.yml +5 -0
- data/lib/generators/pundit/install/templates/application_policy.rb +1 -1
- data/lib/generators/pundit/policy/templates/policy.rb +7 -1
- data/lib/generators/rspec/templates/policy_spec.rb +1 -1
- data/lib/pundit/authorization.rb +12 -4
- data/lib/pundit/cache_store/legacy_store.rb +17 -0
- data/lib/pundit/cache_store/null_store.rb +18 -0
- data/lib/pundit/context.rb +127 -0
- data/lib/pundit/policy_finder.rb +1 -1
- data/lib/pundit/rspec.rb +23 -1
- data/lib/pundit/version.rb +1 -1
- data/lib/pundit.rb +28 -89
- data/pundit.gemspec +4 -2
- data/spec/authorization_spec.rb +23 -7
- data/spec/dsl_spec.rb +30 -0
- data/spec/generators_spec.rb +1 -1
- data/spec/policies/post_policy_spec.rb +27 -0
- data/spec/pundit_spec.rb +35 -14
- data/spec/spec_helper.rb +113 -36
- metadata +26 -13
- data/.travis.yml +0 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1cc7a931867875af2c1a7cd5c4225da689b33e101f76bb7a471afb967323e615
|
4
|
+
data.tar.gz: 8ca35ba01f65b52b1b8bbb2061858bdc61cd0034b01818b07dbbba4b7ddd3a69
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0f495747f61c744c04dffa7811d3a86fc818812807a971591d71542d798d5a7aa4438333534082e755bbead592b4b1b5465e23030e535b03420c643e088bcaf1
|
7
|
+
data.tar.gz: 951ec8a8c02c081bc6b412bb0b5d1d6ffcc33543fa71f66fef9c4f4a6f391ea53a057e20b94bdef5faf4c8f2ef0deffd09357c9580ef6a739575c94a70d9d950
|
@@ -0,0 +1,20 @@
|
|
1
|
+
---
|
2
|
+
name: Bug report
|
3
|
+
about: Create a bug report to report a problem
|
4
|
+
title: ''
|
5
|
+
labels: problem
|
6
|
+
assignees: ''
|
7
|
+
|
8
|
+
---
|
9
|
+
|
10
|
+
**Describe the bug**
|
11
|
+
A clear and concise description of what the bug is.
|
12
|
+
|
13
|
+
**To Reproduce**
|
14
|
+
Steps or runnable code to reproduce the problem.
|
15
|
+
|
16
|
+
**Expected behavior**
|
17
|
+
A clear and concise description of what you expected to happen.
|
18
|
+
|
19
|
+
**Additional context**
|
20
|
+
Add any other context about the problem here.
|
@@ -0,0 +1,26 @@
|
|
1
|
+
---
|
2
|
+
name: Feature request
|
3
|
+
about: Suggest an idea
|
4
|
+
title: ''
|
5
|
+
labels: ['feature request']
|
6
|
+
assignees: ''
|
7
|
+
---
|
8
|
+
|
9
|
+
**Please consider**
|
10
|
+
- Could this feature break backwards-compatibility?
|
11
|
+
- Could this feature benefit the many who use Pundit?
|
12
|
+
- Could this feature be useful in _most_ projects that use Pundit?
|
13
|
+
- Would this feature require Rails?
|
14
|
+
- Am I open to creating a Pull Request with the necessary changes?
|
15
|
+
|
16
|
+
**Is your feature request related to a problem? Please describe.**
|
17
|
+
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
18
|
+
|
19
|
+
**Describe the solution you'd like**
|
20
|
+
A clear and concise description of how you'd like to approach solving the problem.
|
21
|
+
|
22
|
+
**Describe alternatives you've considered**
|
23
|
+
A clear and concise description of any alternative solutions or features you've considered.
|
24
|
+
|
25
|
+
**Additional context**
|
26
|
+
Add any other context. Ex. if you've solved this problem in your own projects already, how that worked, and why the feature should be moved and maintained in Pundit instead.
|
@@ -0,0 +1,8 @@
|
|
1
|
+
## To do
|
2
|
+
|
3
|
+
- [ ] Make changes:
|
4
|
+
- [ ] Bump `Pundit::VERSION` in `lib/pundit/version.rb`.
|
5
|
+
- [ ] Update `CHANGELOG.md`.
|
6
|
+
- [ ] Open pull request 🚀 and merge it.
|
7
|
+
- [ ] Run [push gem](https://github.com/varvet/pundit/actions/workflows/push_gem.yml) GitHub Action.
|
8
|
+
- [ ] Make an announcement in [Pundit discussions](https://github.com/varvet/pundit/discussions/categories/announcements)
|
@@ -0,0 +1,9 @@
|
|
1
|
+
## To do
|
2
|
+
|
3
|
+
- [ ] I have read the [contributing guidelines](https://github.com/varvet/pundit/contribute).
|
4
|
+
- [ ] I have added relevant tests.
|
5
|
+
- [ ] I have adjusted relevant documentation.
|
6
|
+
- [ ] I have made sure the individual commits are meaningful.
|
7
|
+
- [ ] I have added relevant lines to the CHANGELOG.
|
8
|
+
|
9
|
+
PS: Thank you for contributing to Pundit ❤️
|
@@ -0,0 +1,112 @@
|
|
1
|
+
name: Main
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [ "main" ]
|
6
|
+
pull_request:
|
7
|
+
branches: [ "main" ]
|
8
|
+
workflow_dispatch:
|
9
|
+
|
10
|
+
permissions:
|
11
|
+
contents: read
|
12
|
+
|
13
|
+
env:
|
14
|
+
CC_TEST_REPORTER_ID: "ac477089fe20ab4fc7e0d304cab75f72d73d58a7596d366935d18fcc7d51f8f9"
|
15
|
+
|
16
|
+
# `github.ref` points to the *merge commit* when running tests on a pull request, which will be a commit
|
17
|
+
# that doesn't exists in our code base. Since this workflow triggers from a PR, we use the HEAD SHA instead.
|
18
|
+
#
|
19
|
+
# NOTE: These are both used by Code Climate (cc-test-reporter).
|
20
|
+
GIT_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
|
21
|
+
GIT_BRANCH: ${{ github.head_ref }}
|
22
|
+
|
23
|
+
jobs:
|
24
|
+
matrix-test:
|
25
|
+
runs-on: ubuntu-latest
|
26
|
+
continue-on-error: ${{ matrix.allow-failure || false }}
|
27
|
+
strategy:
|
28
|
+
fail-fast: false
|
29
|
+
matrix:
|
30
|
+
ruby-version:
|
31
|
+
- '3.1'
|
32
|
+
- '3.2'
|
33
|
+
- '3.3'
|
34
|
+
- 'jruby-9.3.10' # oldest supported jruby
|
35
|
+
- 'jruby'
|
36
|
+
include: # HEAD-versions
|
37
|
+
- ruby-version: 'head'
|
38
|
+
allow-failure: true
|
39
|
+
- ruby-version: 'jruby-head'
|
40
|
+
allow-failure: true
|
41
|
+
- ruby-version: 'truffleruby-head'
|
42
|
+
allow-failure: true
|
43
|
+
|
44
|
+
steps:
|
45
|
+
- uses: actions/checkout@v4
|
46
|
+
- name: Set up Ruby
|
47
|
+
uses: ruby/setup-ruby@v1
|
48
|
+
with:
|
49
|
+
rubygems: latest
|
50
|
+
ruby-version: ${{ matrix.ruby-version }}
|
51
|
+
bundler-cache: ${{ !startsWith(matrix.ruby-version, 'jruby') }}
|
52
|
+
- name: Bundler install (JRuby workaround)
|
53
|
+
if: ${{ startsWith(matrix.ruby-version, 'jruby') }}
|
54
|
+
run: |
|
55
|
+
gem install psych
|
56
|
+
bundle install
|
57
|
+
- name: Run tests
|
58
|
+
run: bundle exec rspec
|
59
|
+
|
60
|
+
test:
|
61
|
+
runs-on: ubuntu-latest
|
62
|
+
steps:
|
63
|
+
- uses: actions/checkout@v4
|
64
|
+
- name: Set up Ruby
|
65
|
+
uses: ruby/setup-ruby@v1
|
66
|
+
with:
|
67
|
+
rubygems: latest
|
68
|
+
ruby-version: 'ruby'
|
69
|
+
bundler-cache: true
|
70
|
+
- name: "Download cc-test-reporter from codeclimate.com"
|
71
|
+
run: |
|
72
|
+
curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
73
|
+
chmod +x ./cc-test-reporter
|
74
|
+
- name: "Report to Code Climate that we will send a coverage report."
|
75
|
+
run: ./cc-test-reporter before-build
|
76
|
+
- name: Run tests
|
77
|
+
run: bundle exec rspec
|
78
|
+
env:
|
79
|
+
COVERAGE: 1
|
80
|
+
- name: Upload code coverage to Code Climate
|
81
|
+
run: |
|
82
|
+
./cc-test-reporter after-build \
|
83
|
+
--coverage-input-type simplecov \
|
84
|
+
./coverage/.resultset.json
|
85
|
+
|
86
|
+
rubocop:
|
87
|
+
runs-on: ubuntu-latest
|
88
|
+
steps:
|
89
|
+
- uses: actions/checkout@v4
|
90
|
+
- name: Set up Ruby
|
91
|
+
uses: ruby/setup-ruby@v1
|
92
|
+
with:
|
93
|
+
rubygems: default
|
94
|
+
ruby-version: 'ruby'
|
95
|
+
bundler-cache: false
|
96
|
+
- run: bundle install
|
97
|
+
- name: Run RuboCop
|
98
|
+
run: bundle exec rubocop
|
99
|
+
|
100
|
+
required-checks:
|
101
|
+
runs-on: ubuntu-latest
|
102
|
+
if: ${{ always() }}
|
103
|
+
needs:
|
104
|
+
- test
|
105
|
+
- matrix-test
|
106
|
+
- rubocop
|
107
|
+
steps:
|
108
|
+
- name: failure
|
109
|
+
if: ${{ failure() || contains(needs.*.result, 'failure') }}
|
110
|
+
run: exit 1
|
111
|
+
- name: success
|
112
|
+
run: exit 0
|
@@ -0,0 +1,33 @@
|
|
1
|
+
name: Push Gem
|
2
|
+
|
3
|
+
on:
|
4
|
+
workflow_dispatch:
|
5
|
+
|
6
|
+
permissions:
|
7
|
+
contents: read
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
push:
|
11
|
+
if: github.repository == 'varvet/pundit'
|
12
|
+
runs-on: ubuntu-latest
|
13
|
+
|
14
|
+
permissions:
|
15
|
+
contents: write
|
16
|
+
id-token: write
|
17
|
+
|
18
|
+
steps:
|
19
|
+
# Set up
|
20
|
+
- name: Harden Runner
|
21
|
+
uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1
|
22
|
+
with:
|
23
|
+
egress-policy: audit
|
24
|
+
|
25
|
+
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
26
|
+
- name: Set up Ruby
|
27
|
+
uses: ruby/setup-ruby@a6e6f86333f0a2523ece813039b8b4be04560854 # v1.190.0
|
28
|
+
with:
|
29
|
+
bundler-cache: true
|
30
|
+
ruby-version: ruby
|
31
|
+
|
32
|
+
# Release
|
33
|
+
- uses: rubygems/release-gem@612653d273a73bdae1df8453e090060bb4db5f31 # v1+ unreleased
|
data/.rubocop.yml
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
AllCops:
|
2
|
-
TargetRubyVersion:
|
2
|
+
TargetRubyVersion: 3.1
|
3
3
|
Exclude:
|
4
4
|
- "lib/generators/**/templates/**/*"
|
5
|
+
<% `git status --ignored --porcelain`.lines.grep(/^!! /).each do |path| %>
|
6
|
+
- <%= path.sub(/^!! /, '').sub(/\/$/, '/**/*') %>
|
7
|
+
<% end %>
|
5
8
|
SuggestExtensions: false
|
6
9
|
NewCops: disable
|
7
10
|
|
@@ -20,15 +23,6 @@ Metrics/ModuleLength:
|
|
20
23
|
Layout/LineLength:
|
21
24
|
Max: 120
|
22
25
|
|
23
|
-
Metrics/AbcSize:
|
24
|
-
Enabled: false
|
25
|
-
|
26
|
-
Metrics/CyclomaticComplexity:
|
27
|
-
Enabled: false
|
28
|
-
|
29
|
-
Metrics/PerceivedComplexity:
|
30
|
-
Enabled: false
|
31
|
-
|
32
26
|
Gemspec/RequiredRubyVersion:
|
33
27
|
Enabled: false
|
34
28
|
|
@@ -59,14 +53,11 @@ Style/StringLiteralsInInterpolation:
|
|
59
53
|
Style/StructInheritance:
|
60
54
|
Enabled: false
|
61
55
|
|
62
|
-
Style/AndOr:
|
63
|
-
Enabled: false
|
64
|
-
|
65
|
-
Style/Not:
|
66
|
-
Enabled: false
|
67
|
-
|
68
56
|
Style/DoubleNegation:
|
69
57
|
Enabled: false
|
70
58
|
|
71
59
|
Style/Documentation:
|
72
60
|
Enabled: false # TODO: Enable again once we have more docs
|
61
|
+
|
62
|
+
Style/HashSyntax:
|
63
|
+
EnforcedShorthandSyntax: never
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,45 @@
|
|
1
1
|
# Pundit
|
2
2
|
|
3
|
+
## Unreleased
|
4
|
+
|
5
|
+
## 2.4.0 (2024-08-26)
|
6
|
+
|
7
|
+
## Changed
|
8
|
+
|
9
|
+
- Improve the `NotAuthorizedError` message to include the policy class.
|
10
|
+
Furthermore, in the case where the record passed is a class instead of an instance, the class name is given. (#812)
|
11
|
+
|
12
|
+
## Added
|
13
|
+
|
14
|
+
- Add customizable permit matcher description (#806)
|
15
|
+
- Add support for filter_run_when_matching :focus with permissions helper. (#820)
|
16
|
+
|
17
|
+
## 2.3.2 (2024-05-08)
|
18
|
+
|
19
|
+
- Refactor: First pass of Pundit::Context (#797)
|
20
|
+
|
21
|
+
## Changed
|
22
|
+
|
23
|
+
- Update `ApplicationPolicy` generator to qualify the `Scope` class name (#792)
|
24
|
+
- Policy generator uses `NoMethodError` to indicate `#resolve` is not implemented (#776)
|
25
|
+
|
26
|
+
## Deprecated
|
27
|
+
|
28
|
+
- Dropped support for Ruby 3.0 (#796)
|
29
|
+
|
30
|
+
## 2.3.1 (2023-07-17)
|
31
|
+
|
32
|
+
### Fixed
|
33
|
+
|
34
|
+
- Use `Kernel.warn` instead of `ActiveSupport::Deprecation.warn` for deprecations (#764)
|
35
|
+
- Policy generator now works on Ruby 3.2 (#754)
|
36
|
+
|
37
|
+
## 2.3.0 (2022-12-19)
|
38
|
+
|
39
|
+
### Added
|
40
|
+
|
41
|
+
- add support for rubocop-rspec syntax extensions (#745)
|
42
|
+
|
3
43
|
## 2.2.0 (2022-02-11)
|
4
44
|
|
5
45
|
### Fixed
|
data/CODE_OF_CONDUCT.md
CHANGED
@@ -25,4 +25,4 @@ maintainers.
|
|
25
25
|
|
26
26
|
This Code of Conduct is adapted from the [Contributor
|
27
27
|
Covenant](http:contributor-covenant.org), version 1.0.0, available at
|
28
|
-
[
|
28
|
+
[https://contributor-covenant.org/version/1/0/0/](https://contributor-covenant.org/version/1/0/0/)
|
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
|
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/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,31 +1,29 @@
|
|
1
1
|
# Pundit
|
2
2
|
|
3
|
-
[](
|
3
|
+
[](https://github.com/varvet/pundit/actions/workflows/main.yml)
|
4
|
+
[](https://codeclimate.com/github/varvet/pundit/maintainability)
|
5
|
+
[](https://inch-ci.org/github/varvet/pundit)
|
6
|
+
[](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
|
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](
|
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/
|
17
|
-
- [Code of Conduct](https://github.com/varvet/pundit/blob/
|
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
|
-
```
|
28
|
-
|
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
|
53
|
-
|
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
|
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
|
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
|
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
|
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 :
|
366
|
-
|
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
|
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
|
-
##
|
427
|
+
## Plain old Ruby
|
428
|
+
|
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.
|
423
430
|
|
424
|
-
|
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.
|
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.
|
429
432
|
|
430
|
-
Remember that all of the policy and scope classes are
|
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.
|
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](
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
@@ -692,7 +687,7 @@ You can now retrieve these attributes from the policy:
|
|
692
687
|
class PostsController < ApplicationController
|
693
688
|
def update
|
694
689
|
@post = Post.find(params[:id])
|
695
|
-
if @post.
|
690
|
+
if @post.update(post_params)
|
696
691
|
redirect_to @post
|
697
692
|
else
|
698
693
|
render :edit
|
@@ -714,7 +709,7 @@ However, this is a bit cumbersome, so Pundit provides a convenient helper method
|
|
714
709
|
class PostsController < ApplicationController
|
715
710
|
def update
|
716
711
|
@post = Post.find(params[:id])
|
717
|
-
if @post.
|
712
|
+
if @post.update(permitted_attributes(@post))
|
718
713
|
redirect_to @post
|
719
714
|
else
|
720
715
|
render :edit
|
@@ -766,6 +761,10 @@ end
|
|
766
761
|
|
767
762
|
### Policy Specs
|
768
763
|
|
764
|
+
> [!TIP]
|
765
|
+
> An alternative approach to Pundit policy specs is scoping them to a user context as outlined in this
|
766
|
+
[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.
|
767
|
+
|
769
768
|
Pundit includes a mini-DSL for writing expressive tests for your policies in RSpec.
|
770
769
|
Require `pundit/rspec` in your `spec_helper.rb`:
|
771
770
|
|
@@ -795,25 +794,67 @@ describe PostPolicy do
|
|
795
794
|
end
|
796
795
|
```
|
797
796
|
|
798
|
-
|
799
|
-
|
797
|
+
### Custom matcher description
|
798
|
+
|
799
|
+
By default rspec includes an inspected `user` and `record` in the matcher description, which might become overly verbose:
|
800
|
+
|
801
|
+
```
|
802
|
+
PostPolicy
|
803
|
+
update? and show?
|
804
|
+
is expected to permit #<User:0x0000000104aefd80> and #<Post:0x0000000104aef8d0 @user=#<User:0x0000000104aefd80>>
|
805
|
+
```
|
806
|
+
|
807
|
+
You can override the default description with a static string, or a block:
|
808
|
+
|
809
|
+
```ruby
|
810
|
+
# static alternative: Pundit::RSpec::Matchers.description = "permit the user"
|
811
|
+
Pundit::RSpec::Matchers.description = ->(user, record) do
|
812
|
+
"permit user with role #{user.role} to access record with ID #{record.id}"
|
813
|
+
end
|
814
|
+
```
|
815
|
+
|
816
|
+
Which would make for a less chatty output:
|
817
|
+
|
818
|
+
```
|
819
|
+
PostPolicy
|
820
|
+
update? and show?
|
821
|
+
is expected to permit user with role admin to access record with ID 130
|
822
|
+
```
|
823
|
+
|
824
|
+
### Focus Support
|
825
|
+
|
826
|
+
If your RSpec config has `filter_run_when_matching :focus`, you may tag the `permissions` helper like so:
|
827
|
+
|
828
|
+
```
|
829
|
+
permissions :show?, :focus do
|
830
|
+
```
|
800
831
|
|
801
832
|
### Scope Specs
|
802
833
|
|
803
|
-
Pundit does not provide a DSL for testing scopes.
|
834
|
+
Pundit does not provide a DSL for testing scopes. Test them like you would a regular Ruby class!
|
835
|
+
|
836
|
+
### Linting with RuboCop RSpec
|
837
|
+
|
838
|
+
When you lint your RSpec spec files with `rubocop-rspec`, it will fail to properly detect RSpec constructs that Pundit defines, `permissions`.
|
839
|
+
Make sure to use `rubocop-rspec` 2.0 or newer and add the following to your `.rubocop.yml`:
|
840
|
+
|
841
|
+
```yaml
|
842
|
+
inherit_gem:
|
843
|
+
pundit: config/rubocop-rspec.yml
|
844
|
+
```
|
804
845
|
|
805
846
|
# External Resources
|
806
847
|
|
807
848
|
- [RailsApps Example Application: Pundit and Devise](https://github.com/RailsApps/rails-devise-pundit)
|
808
|
-
- [Migrating to Pundit from CanCan](
|
809
|
-
- [Testing Pundit Policies with RSpec](
|
849
|
+
- [Migrating to Pundit from CanCan](https://blog.carbonfive.com/2013/10/21/migrating-to-pundit-from-cancan/)
|
850
|
+
- [Testing Pundit Policies with RSpec](https://thunderboltlabs.com/blog/2013/03/27/testing-pundit-policies-with-rspec/)
|
810
851
|
- [Testing Pundit with Minitest](https://github.com/varvet/pundit/issues/204#issuecomment-60166450)
|
811
852
|
- [Using Pundit outside of a Rails controller](https://github.com/varvet/pundit/pull/136)
|
812
|
-
- [Straightforward Rails Authorization with Pundit](
|
853
|
+
- [Straightforward Rails Authorization with Pundit](https://www.sitepoint.com/straightforward-rails-authorization-with-pundit/)
|
813
854
|
|
814
855
|
## Other implementations
|
815
856
|
|
816
|
-
- [Flask-Pundit](https://github.com/anurag90x/flask-pundit) (Python) is a [Flask](
|
857
|
+
- [Flask-Pundit](https://github.com/anurag90x/flask-pundit) (Python) is a [Flask](https://flask.pocoo.org/) extension "heavily inspired by" Pundit
|
817
858
|
|
818
859
|
# License
|
819
860
|
|