pundit 2.0.0 → 2.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/pull_request_template.md +9 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +21 -52
- data/.travis.yml +20 -14
- data/CHANGELOG.md +85 -3
- data/CONTRIBUTING.md +1 -4
- data/Gemfile +2 -11
- data/LICENSE.txt +1 -1
- data/README.md +91 -57
- data/Rakefile +2 -0
- data/SECURITY.md +19 -0
- data/config/rubocop-rspec.yml +5 -0
- data/lib/generators/pundit/install/install_generator.rb +4 -2
- data/lib/generators/pundit/install/templates/application_policy.rb +7 -3
- data/lib/generators/pundit/policy/policy_generator.rb +4 -2
- data/lib/generators/pundit/policy/templates/policy.rb +4 -3
- data/lib/generators/rspec/policy_generator.rb +4 -2
- data/lib/generators/rspec/templates/policy_spec.rb +2 -2
- data/lib/generators/test_unit/policy_generator.rb +4 -2
- data/lib/pundit/authorization.rb +168 -0
- data/lib/pundit/policy_finder.rb +3 -1
- data/lib/pundit/rspec.rb +6 -14
- data/lib/pundit/version.rb +1 -1
- data/lib/pundit.rb +47 -184
- data/pundit.gemspec +17 -3
- data/spec/authorization_spec.rb +258 -0
- data/spec/generators_spec.rb +43 -0
- data/spec/policies/post_policy_spec.rb +3 -1
- data/spec/policy_finder_spec.rb +82 -17
- data/spec/pundit_spec.rb +61 -218
- data/spec/spec_helper.rb +44 -26
- metadata +158 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b5c9e118c59bc3a683734817ac6fb9036a2b909df7abce2dbbdc00fc16aebdf7
|
4
|
+
data.tar.gz: 843cc1b7652e88d598a37a28f93bf13c41710bf3dddefeb96acf74e659279581
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f2430ece33471f7a321a124aeafab7dbc3be4688fbda581b758d90649f4ae06d0cbaf86df768e881d0a2f1c0ab55581cb5dc0f1d3012ab7611b2fd81b8a0f321
|
7
|
+
data.tar.gz: 3432cc545ca5139cfcd7e1fc26a17d0882c11de71a3c6949c1d1da232183eba495de18aa06b64462c1233b820099788b43feeb0e9b439911bc9761dc7bd1e141
|
@@ -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 ❤️
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
@@ -1,10 +1,9 @@
|
|
1
1
|
AllCops:
|
2
|
-
|
3
|
-
TargetRubyVersion: 2.1
|
2
|
+
TargetRubyVersion: 2.6
|
4
3
|
Exclude:
|
5
|
-
- "
|
6
|
-
|
7
|
-
|
4
|
+
- "lib/generators/**/templates/**/*"
|
5
|
+
SuggestExtensions: false
|
6
|
+
NewCops: disable
|
8
7
|
|
9
8
|
Metrics/BlockLength:
|
10
9
|
Exclude:
|
@@ -18,7 +17,7 @@ Metrics/ModuleLength:
|
|
18
17
|
Exclude:
|
19
18
|
- "**/*_spec.rb"
|
20
19
|
|
21
|
-
|
20
|
+
Layout/LineLength:
|
22
21
|
Max: 120
|
23
22
|
|
24
23
|
Metrics/AbcSize:
|
@@ -30,33 +29,12 @@ Metrics/CyclomaticComplexity:
|
|
30
29
|
Metrics/PerceivedComplexity:
|
31
30
|
Enabled: false
|
32
31
|
|
33
|
-
|
34
|
-
|
32
|
+
Gemspec/RequiredRubyVersion:
|
33
|
+
Enabled: false
|
35
34
|
|
36
|
-
Layout/
|
35
|
+
Layout/ParameterAlignment:
|
37
36
|
EnforcedStyle: with_fixed_indentation
|
38
37
|
|
39
|
-
Style/StringLiterals:
|
40
|
-
EnforcedStyle: double_quotes
|
41
|
-
|
42
|
-
Style/StringLiteralsInInterpolation:
|
43
|
-
EnforcedStyle: double_quotes
|
44
|
-
|
45
|
-
Layout/ClosingParenthesisIndentation:
|
46
|
-
Enabled: false
|
47
|
-
|
48
|
-
Style/OneLineConditional:
|
49
|
-
Enabled: false
|
50
|
-
|
51
|
-
Style/AndOr:
|
52
|
-
Enabled: false
|
53
|
-
|
54
|
-
Style/Not:
|
55
|
-
Enabled: false
|
56
|
-
|
57
|
-
Documentation:
|
58
|
-
Enabled: false # TODO: Enable again once we have more docs
|
59
|
-
|
60
38
|
Layout/CaseIndentation:
|
61
39
|
EnforcedStyle: case
|
62
40
|
SupportedStyles:
|
@@ -64,40 +42,31 @@ Layout/CaseIndentation:
|
|
64
42
|
- end
|
65
43
|
IndentOneStep: true
|
66
44
|
|
45
|
+
Layout/EndAlignment:
|
46
|
+
EnforcedStyleAlignWith: variable
|
47
|
+
|
67
48
|
Style/PercentLiteralDelimiters:
|
68
49
|
PreferredDelimiters:
|
69
50
|
'%w': "[]"
|
70
51
|
'%W': "[]"
|
71
52
|
|
72
|
-
|
73
|
-
EnforcedStyle:
|
74
|
-
|
75
|
-
Style/SignalException:
|
76
|
-
Enabled: false
|
77
|
-
|
78
|
-
Layout/IndentationWidth:
|
79
|
-
Enabled: false
|
80
|
-
|
81
|
-
Style/TrivialAccessors:
|
82
|
-
ExactNameMatch: true
|
83
|
-
|
84
|
-
Layout/EndAlignment:
|
85
|
-
EnforcedStyleAlignWith: variable
|
86
|
-
|
87
|
-
Layout/DefEndAlignment:
|
88
|
-
Enabled: false
|
53
|
+
Style/StringLiterals:
|
54
|
+
EnforcedStyle: double_quotes
|
89
55
|
|
90
|
-
|
91
|
-
|
56
|
+
Style/StringLiteralsInInterpolation:
|
57
|
+
EnforcedStyle: double_quotes
|
92
58
|
|
93
|
-
Style/
|
59
|
+
Style/StructInheritance:
|
94
60
|
Enabled: false
|
95
61
|
|
96
|
-
Style/
|
62
|
+
Style/AndOr:
|
97
63
|
Enabled: false
|
98
64
|
|
99
|
-
|
65
|
+
Style/Not:
|
100
66
|
Enabled: false
|
101
67
|
|
102
68
|
Style/DoubleNegation:
|
103
69
|
Enabled: false
|
70
|
+
|
71
|
+
Style/Documentation:
|
72
|
+
Enabled: false # TODO: Enable again once we have more docs
|
data/.travis.yml
CHANGED
@@ -1,21 +1,27 @@
|
|
1
1
|
language: ruby
|
2
|
-
|
3
|
-
before_install:
|
4
|
-
- gem update --system
|
5
|
-
- gem install bundler
|
2
|
+
dist: focal
|
6
3
|
|
7
4
|
matrix:
|
8
5
|
include:
|
9
|
-
-
|
6
|
+
- name: "RuboCop lint on pre-installed Ruby version"
|
7
|
+
rvm: 2.7.1 # Pre-installed Ruby version
|
8
|
+
before_install:
|
9
|
+
- gem install bundler
|
10
10
|
script: bundle exec rake rubocop # ONLY lint once, first
|
11
|
-
- rvm: 2.
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
- rvm:
|
11
|
+
- rvm: 2.6.7
|
12
|
+
before_script:
|
13
|
+
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
14
|
+
- chmod +x ./cc-test-reporter
|
15
|
+
- ./cc-test-reporter before-build
|
16
|
+
after_script:
|
17
|
+
- ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
|
18
|
+
- rvm: 2.7.3
|
19
|
+
- rvm: 3.0.1
|
20
|
+
- rvm: 3.1.0
|
21
|
+
- rvm: 3.2.0
|
22
|
+
- rvm: jruby-9.3.10.0
|
20
23
|
env:
|
21
24
|
- JRUBY_OPTS="--debug"
|
25
|
+
- rvm: truffleruby-head
|
26
|
+
allow_failures:
|
27
|
+
- rvm: truffleruby-head
|
data/CHANGELOG.md
CHANGED
@@ -1,21 +1,103 @@
|
|
1
1
|
# Pundit
|
2
2
|
|
3
|
+
## Unreleased
|
4
|
+
|
5
|
+
Nothing.
|
6
|
+
|
7
|
+
## 2.3.1 (2023-07-17)
|
8
|
+
|
9
|
+
### Fixed
|
10
|
+
|
11
|
+
- Use `Kernel.warn` instead of `ActiveSupport::Deprecation.warn` for deprecations (#764)
|
12
|
+
- Policy generator now works on Ruby 3.2 (#754)
|
13
|
+
|
14
|
+
## 2.3.0 (2022-12-19)
|
15
|
+
|
16
|
+
### Added
|
17
|
+
|
18
|
+
- add support for rubocop-rspec syntax extensions (#745)
|
19
|
+
|
20
|
+
## 2.2.0 (2022-02-11)
|
21
|
+
|
22
|
+
### Fixed
|
23
|
+
|
24
|
+
- Using `policy_class` and a namespaced record now passes only the record when instantiating the policy. (#697, #689, #694, #666)
|
25
|
+
|
26
|
+
### Changed
|
27
|
+
|
28
|
+
- Require users to explicitly define Scope#resolve in generated policies (#711, #722)
|
29
|
+
|
30
|
+
### Deprecated
|
31
|
+
|
32
|
+
- Deprecate `include Pundit` in favor of `include Pundit::Authorization` (#621)
|
33
|
+
|
34
|
+
## 2.1.1 (2021-08-13)
|
35
|
+
|
36
|
+
Friday 13th-release!
|
37
|
+
|
38
|
+
Careful! The bugfix below (#626) could break existing code. If you rely on the
|
39
|
+
return value for `authorize` and namespaced policies you might need to do some
|
40
|
+
changes.
|
41
|
+
|
42
|
+
### Fixed
|
43
|
+
|
44
|
+
- `.authorize` and `#authorize` return the instance, even for namespaced
|
45
|
+
policies (#626)
|
46
|
+
|
47
|
+
### Changed
|
48
|
+
|
49
|
+
- Generate application scope with `protected` attr_readers. (#616)
|
50
|
+
|
51
|
+
### Removed
|
52
|
+
|
53
|
+
- Dropped support for Ruby end-of-life versions: 2.1 and 2.2. (#604)
|
54
|
+
- Dropped support for Ruby end-of-life versions: 2.3 (#633)
|
55
|
+
- Dropped support for Ruby end-of-life versions: 2.4, 2.5 and JRuby 9.1 (#676)
|
56
|
+
- Dropped support for RSpec 2 (#615)
|
57
|
+
|
58
|
+
## 2.1.0 (2019-08-14)
|
59
|
+
|
60
|
+
### Fixed
|
61
|
+
|
62
|
+
- Avoid name clashes with the Error class. (#590)
|
63
|
+
|
64
|
+
### Changed
|
65
|
+
|
66
|
+
- Return a safer default NotAuthorizedError message. (#583)
|
67
|
+
|
68
|
+
## 2.0.1 (2019-01-18)
|
69
|
+
|
70
|
+
### Breaking changes
|
71
|
+
|
72
|
+
None
|
73
|
+
|
74
|
+
### Other changes
|
75
|
+
|
76
|
+
- Improve exception handling for `#policy_scope` and `#policy_scope!`. (#550)
|
77
|
+
- Add `:policy` metadata to RSpec template. (#566)
|
78
|
+
|
3
79
|
## 2.0.0 (2018-07-21)
|
4
80
|
|
5
81
|
No changes since beta1
|
6
82
|
|
7
83
|
## 2.0.0.beta1 (2018-07-04)
|
8
84
|
|
85
|
+
### Breaking changes
|
86
|
+
|
87
|
+
- Only pass last element of "namespace array" to policy and scope. (#529)
|
88
|
+
- Raise `InvalidConstructorError` if a policy or policy scope with an invalid constructor is called. (#462)
|
89
|
+
- Return passed object from `#authorize` method to make chaining possible. (#385)
|
90
|
+
|
91
|
+
### Other changes
|
92
|
+
|
9
93
|
- Add `policy_class` option to `authorize` to be able to override the policy. (#441)
|
10
94
|
- Add `policy_scope_class` option to `authorize` to be able to override the policy scope. (#441)
|
11
95
|
- Fix `param_key` issue when passed an array. (#529)
|
12
|
-
- Only pass last element of "namespace array" to policy and scope. (#529)
|
13
96
|
- Allow specification of a `NilClassPolicy`. (#525)
|
14
97
|
- Make sure `policy_class` override is called when passed an array. (#475)
|
15
|
-
|
98
|
+
|
16
99
|
- Use `action_name` instead of `params[:action]`. (#419)
|
17
100
|
- Add `pundit_params_for` method to make it easy to customize params fetching. (#502)
|
18
|
-
- Return passed object from `#authorize` method to make chaining possible. (#385)
|
19
101
|
|
20
102
|
## 1.1.0 (2016-01-14)
|
21
103
|
|
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
|
|
data/Gemfile
CHANGED
@@ -1,16 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
source "https://rubygems.org"
|
2
4
|
|
3
5
|
ruby RUBY_VERSION
|
4
6
|
|
5
7
|
gemspec
|
6
|
-
|
7
|
-
group :development, :test do
|
8
|
-
gem "actionpack"
|
9
|
-
gem "activemodel"
|
10
|
-
gem "bundler"
|
11
|
-
gem "pry"
|
12
|
-
gem "rake"
|
13
|
-
gem "rspec"
|
14
|
-
gem "rubocop"
|
15
|
-
gem "yard"
|
16
|
-
end
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
# Pundit
|
2
2
|
|
3
|
-
[![Build Status](https://
|
3
|
+
[![Build Status](https://app.travis-ci.com/varvet/pundit.svg?branch=main)](https://app.travis-ci.com/varvet/pundit)
|
4
4
|
[![Code Climate](https://codeclimate.com/github/varvet/pundit.svg)](https://codeclimate.com/github/varvet/pundit)
|
5
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
|
9
|
-
classes and object oriented design patterns to build a
|
10
|
-
|
9
|
+
classes and object oriented design patterns to build a straightforward, robust, and
|
10
|
+
scalable authorization system.
|
11
11
|
|
12
12
|
Links:
|
13
13
|
|
14
|
-
- [API documentation](http://www.rubydoc.info/gems/pundit)
|
14
|
+
- [API documentation for the most recent version](http://www.rubydoc.info/gems/pundit)
|
15
15
|
- [Source Code](https://github.com/varvet/pundit)
|
16
16
|
- [Contributing](https://github.com/varvet/pundit/blob/master/CONTRIBUTING.md)
|
17
17
|
- [Code of Conduct](https://github.com/varvet/pundit/blob/master/CODE_OF_CONDUCT.md)
|
@@ -22,16 +22,17 @@ Sponsored by:
|
|
22
22
|
|
23
23
|
## Installation
|
24
24
|
|
25
|
-
|
26
|
-
|
25
|
+
> **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
|
+
|
27
|
+
``` sh
|
28
|
+
bundle add pundit
|
27
29
|
```
|
28
30
|
|
29
|
-
Include Pundit in your application controller:
|
31
|
+
Include `Pundit::Authorization` in your application controller:
|
30
32
|
|
31
33
|
``` ruby
|
32
34
|
class ApplicationController < ActionController::Base
|
33
|
-
include Pundit
|
34
|
-
protect_from_forgery
|
35
|
+
include Pundit::Authorization
|
35
36
|
end
|
36
37
|
```
|
37
38
|
|
@@ -48,8 +49,8 @@ can pick up any classes in the new `app/policies/` directory.
|
|
48
49
|
## Policies
|
49
50
|
|
50
51
|
Pundit is focused around the notion of policy classes. We suggest that you put
|
51
|
-
these classes in `app/policies`. This is
|
52
|
-
|
52
|
+
these classes in `app/policies`. This is an example that allows updating a post
|
53
|
+
if the user is an admin, or if the post is unpublished:
|
53
54
|
|
54
55
|
``` ruby
|
55
56
|
class PostPolicy
|
@@ -61,12 +62,12 @@ class PostPolicy
|
|
61
62
|
end
|
62
63
|
|
63
64
|
def update?
|
64
|
-
user.admin?
|
65
|
+
user.admin? || !post.published?
|
65
66
|
end
|
66
67
|
end
|
67
68
|
```
|
68
69
|
|
69
|
-
As you can see, this is
|
70
|
+
As you can see, this is a plain Ruby class. Pundit makes the following
|
70
71
|
assumptions about this class:
|
71
72
|
|
72
73
|
- The class has the same name as some kind of model class, only suffixed
|
@@ -165,13 +166,18 @@ def admin_list
|
|
165
166
|
end
|
166
167
|
```
|
167
168
|
|
168
|
-
`authorize` returns the
|
169
|
+
`authorize` returns the instance passed to it, so you can chain it like this:
|
169
170
|
|
170
171
|
Controller:
|
171
172
|
```ruby
|
172
173
|
def show
|
173
174
|
@user = authorize User.find(params[:id])
|
174
175
|
end
|
176
|
+
|
177
|
+
# return the record even for namespaced policies
|
178
|
+
def show
|
179
|
+
@user = authorize [:admin, User.find(params[:id])]
|
180
|
+
end
|
175
181
|
```
|
176
182
|
|
177
183
|
You can easily get a hold of an instance of the policy through the `policy`
|
@@ -190,14 +196,30 @@ you can retrieve it by passing a symbol.
|
|
190
196
|
|
191
197
|
```ruby
|
192
198
|
# app/policies/dashboard_policy.rb
|
193
|
-
class DashboardPolicy
|
194
|
-
|
199
|
+
class DashboardPolicy
|
200
|
+
attr_reader :user
|
201
|
+
|
202
|
+
# `_record` in this example will be :dashboard
|
203
|
+
def initialize(user, _record)
|
204
|
+
@user = user
|
205
|
+
end
|
206
|
+
|
207
|
+
def show?
|
208
|
+
user.admin?
|
209
|
+
end
|
195
210
|
end
|
196
211
|
```
|
197
212
|
|
213
|
+
Note that the headless policy still needs to accept two arguments. The
|
214
|
+
second argument will be the symbol `:dashboard` in this case, which
|
215
|
+
is what is passed as the record to `authorize` below.
|
216
|
+
|
198
217
|
```ruby
|
199
218
|
# In controllers
|
200
|
-
|
219
|
+
def show
|
220
|
+
authorize :dashboard, :show?
|
221
|
+
...
|
222
|
+
end
|
201
223
|
```
|
202
224
|
|
203
225
|
```erb
|
@@ -216,8 +238,6 @@ define a class called a policy scope. It can look something like this:
|
|
216
238
|
``` ruby
|
217
239
|
class PostPolicy < ApplicationPolicy
|
218
240
|
class Scope
|
219
|
-
attr_reader :user, :scope
|
220
|
-
|
221
241
|
def initialize(user, scope)
|
222
242
|
@user = user
|
223
243
|
@scope = scope
|
@@ -230,6 +250,10 @@ class PostPolicy < ApplicationPolicy
|
|
230
250
|
scope.where(published: true)
|
231
251
|
end
|
232
252
|
end
|
253
|
+
|
254
|
+
private
|
255
|
+
|
256
|
+
attr_reader :user, :scope
|
233
257
|
end
|
234
258
|
|
235
259
|
def update?
|
@@ -292,13 +316,11 @@ def index
|
|
292
316
|
end
|
293
317
|
```
|
294
318
|
|
295
|
-
|
296
|
-
the `PostPolicy::Scope` class, it will instantiate this class and call
|
297
|
-
`resolve` on the instance. In this case it is a shortcut for doing:
|
319
|
+
In this case it is a shortcut for doing:
|
298
320
|
|
299
321
|
``` ruby
|
300
322
|
def index
|
301
|
-
@
|
323
|
+
@publications = PublicationPolicy::Scope.new(current_user, Post).resolve
|
302
324
|
end
|
303
325
|
```
|
304
326
|
|
@@ -326,7 +348,7 @@ that you haven't forgotten to authorize the action. For example:
|
|
326
348
|
|
327
349
|
``` ruby
|
328
350
|
class ApplicationController < ActionController::Base
|
329
|
-
include Pundit
|
351
|
+
include Pundit::Authorization
|
330
352
|
after_action :verify_authorized
|
331
353
|
end
|
332
354
|
```
|
@@ -339,7 +361,7 @@ authorize individual instances.
|
|
339
361
|
|
340
362
|
``` ruby
|
341
363
|
class ApplicationController < ActionController::Base
|
342
|
-
include Pundit
|
364
|
+
include Pundit::Authorization
|
343
365
|
after_action :verify_authorized, except: :index
|
344
366
|
after_action :verify_policy_scoped, only: :index
|
345
367
|
end
|
@@ -352,7 +374,7 @@ these filters without affecting how your app works in any way.**
|
|
352
374
|
|
353
375
|
Some people have found this feature confusing, while many others
|
354
376
|
find it extremely helpful. If you fall into the category of people who find it
|
355
|
-
confusing then you do not need to use it. Pundit will work
|
377
|
+
confusing then you do not need to use it. Pundit will work fine without
|
356
378
|
using `verify_authorized` and `verify_policy_scoped`.
|
357
379
|
|
358
380
|
### Conditional verification
|
@@ -387,20 +409,23 @@ class Post
|
|
387
409
|
end
|
388
410
|
```
|
389
411
|
|
390
|
-
|
412
|
+
Alternatively, you can declare an instance method:
|
413
|
+
|
414
|
+
``` ruby
|
415
|
+
class Post
|
416
|
+
def policy_class
|
417
|
+
PostablePolicy
|
418
|
+
end
|
419
|
+
end
|
420
|
+
```
|
421
|
+
|
422
|
+
## Plain old Ruby
|
423
|
+
|
424
|
+
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.
|
391
425
|
|
392
|
-
|
393
|
-
yourself. It's a very small library, it just provides a few neat helpers.
|
394
|
-
Together these give you the power of building a well structured, fully working
|
395
|
-
authorization system without using any special DSLs or funky syntax or
|
396
|
-
anything.
|
426
|
+
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.
|
397
427
|
|
398
|
-
Remember that all of the policy and scope classes are
|
399
|
-
which means you can use the same mechanisms you always use to DRY things up.
|
400
|
-
Encapsulate a set of permissions into a module and include them in multiple
|
401
|
-
policies. Use `alias_method` to make some permissions behave the same as
|
402
|
-
others. Inherit from a base set of permissions. Use metaprogramming if you
|
403
|
-
really have to.
|
428
|
+
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.
|
404
429
|
|
405
430
|
## Generator
|
406
431
|
|
@@ -472,8 +497,7 @@ method in every controller.
|
|
472
497
|
|
473
498
|
```ruby
|
474
499
|
class ApplicationController < ActionController::Base
|
475
|
-
|
476
|
-
include Pundit
|
500
|
+
include Pundit::Authorization
|
477
501
|
|
478
502
|
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
|
479
503
|
|
@@ -481,7 +505,7 @@ class ApplicationController < ActionController::Base
|
|
481
505
|
|
482
506
|
def user_not_authorized
|
483
507
|
flash[:alert] = "You are not authorized to perform this action."
|
484
|
-
|
508
|
+
redirect_back(fallback_location: root_path)
|
485
509
|
end
|
486
510
|
end
|
487
511
|
```
|
@@ -510,7 +534,7 @@ class ApplicationController < ActionController::Base
|
|
510
534
|
policy_name = exception.policy.class.to_s.underscore
|
511
535
|
|
512
536
|
flash[:error] = t "#{policy_name}.#{exception.query}", scope: "pundit", default: :default
|
513
|
-
|
537
|
+
redirect_back(fallback_location: root_path)
|
514
538
|
end
|
515
539
|
end
|
516
540
|
```
|
@@ -524,8 +548,7 @@ en:
|
|
524
548
|
create?: 'You cannot create posts!'
|
525
549
|
```
|
526
550
|
|
527
|
-
|
528
|
-
your error messaging.
|
551
|
+
This is an example. Pundit is agnostic as to how you implement your error messaging.
|
529
552
|
|
530
553
|
## Manually retrieving policies and scopes
|
531
554
|
|
@@ -547,9 +570,7 @@ those without the bang will return nil.
|
|
547
570
|
|
548
571
|
## Customize Pundit user
|
549
572
|
|
550
|
-
|
551
|
-
`current_user` is not the method that should be invoked by Pundit. Simply
|
552
|
-
define a method in your controller called `pundit_user`.
|
573
|
+
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`.
|
553
574
|
|
554
575
|
```ruby
|
555
576
|
def pundit_user
|
@@ -593,8 +614,7 @@ class Admin::PostController < AdminController
|
|
593
614
|
end
|
594
615
|
|
595
616
|
def show
|
596
|
-
post = Post.find(params[:id])
|
597
|
-
authorize(post)
|
617
|
+
post = authorize Post.find(params[:id])
|
598
618
|
end
|
599
619
|
end
|
600
620
|
```
|
@@ -627,7 +647,7 @@ class UserContext
|
|
627
647
|
end
|
628
648
|
|
629
649
|
class ApplicationController
|
630
|
-
include Pundit
|
650
|
+
include Pundit::Authorization
|
631
651
|
|
632
652
|
def pundit_user
|
633
653
|
UserContext.new(current_user, request.ip)
|
@@ -637,9 +657,8 @@ end
|
|
637
657
|
|
638
658
|
## Strong parameters
|
639
659
|
|
640
|
-
In Rails
|
641
|
-
|
642
|
-
mass-assignment protection is handled in the controller. With Pundit you can
|
660
|
+
In Rails,
|
661
|
+
mass-assignment protection is handled in the controller. With Pundit you can
|
643
662
|
control which attributes a user has access to update via your policies. You can
|
644
663
|
set up a `permitted_attributes` method in your policy like this:
|
645
664
|
|
@@ -663,7 +682,7 @@ You can now retrieve these attributes from the policy:
|
|
663
682
|
class PostsController < ApplicationController
|
664
683
|
def update
|
665
684
|
@post = Post.find(params[:id])
|
666
|
-
if @post.
|
685
|
+
if @post.update(post_params)
|
667
686
|
redirect_to @post
|
668
687
|
else
|
669
688
|
render :edit
|
@@ -685,7 +704,7 @@ However, this is a bit cumbersome, so Pundit provides a convenient helper method
|
|
685
704
|
class PostsController < ApplicationController
|
686
705
|
def update
|
687
706
|
@post = Post.find(params[:id])
|
688
|
-
if @post.
|
707
|
+
if @post.update(permitted_attributes(@post))
|
689
708
|
redirect_to @post
|
690
709
|
else
|
691
710
|
render :edit
|
@@ -767,20 +786,35 @@ end
|
|
767
786
|
```
|
768
787
|
|
769
788
|
An alternative approach to Pundit policy specs is scoping them to a user context as outlined in this
|
770
|
-
[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/
|
789
|
+
[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/punditcommunity/pundit-matchers) gem.
|
771
790
|
|
772
791
|
### Scope Specs
|
773
792
|
|
774
|
-
Pundit does not provide a DSL for testing scopes.
|
793
|
+
Pundit does not provide a DSL for testing scopes. Test them like you would a regular Ruby class!
|
794
|
+
|
795
|
+
### Linting with RuboCop RSpec
|
796
|
+
|
797
|
+
When you lint your RSpec spec files with `rubocop-rspec`, it will fail to properly detect RSpec constructs that Pundit defines, `permissions`.
|
798
|
+
Make sure to use `rubocop-rspec` 2.0 or newer and add the following to your `.rubocop.yml`:
|
799
|
+
|
800
|
+
```yaml
|
801
|
+
inherit_gem:
|
802
|
+
pundit: config/rubocop-rspec.yml
|
803
|
+
```
|
775
804
|
|
776
805
|
# External Resources
|
777
806
|
|
778
807
|
- [RailsApps Example Application: Pundit and Devise](https://github.com/RailsApps/rails-devise-pundit)
|
779
808
|
- [Migrating to Pundit from CanCan](http://blog.carbonfive.com/2013/10/21/migrating-to-pundit-from-cancan/)
|
780
809
|
- [Testing Pundit Policies with RSpec](http://thunderboltlabs.com/blog/2013/03/27/testing-pundit-policies-with-rspec/)
|
810
|
+
- [Testing Pundit with Minitest](https://github.com/varvet/pundit/issues/204#issuecomment-60166450)
|
781
811
|
- [Using Pundit outside of a Rails controller](https://github.com/varvet/pundit/pull/136)
|
782
812
|
- [Straightforward Rails Authorization with Pundit](http://www.sitepoint.com/straightforward-rails-authorization-with-pundit/)
|
783
813
|
|
814
|
+
## Other implementations
|
815
|
+
|
816
|
+
- [Flask-Pundit](https://github.com/anurag90x/flask-pundit) (Python) is a [Flask](http://flask.pocoo.org/) extension "heavily inspired by" Pundit
|
817
|
+
|
784
818
|
# License
|
785
819
|
|
786
820
|
Licensed under the MIT license, see the separate LICENSE.txt file.
|