consul 1.3.1 → 2.0.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/workflows/test.yml +30 -25
- data/.gitignore +1 -0
- data/.ruby-version +1 -1
- data/CHANGELOG.md +25 -0
- data/Gemfile +1 -1
- data/Gemfile.6-1 +1 -1
- data/Gemfile.6-1.lock +13 -13
- data/{Gemfile.5-2 → Gemfile.7-1} +3 -4
- data/Gemfile.7-1.lock +171 -0
- data/Gemfile.7-2 +17 -0
- data/Gemfile.7-2.lock +171 -0
- data/{Gemfile.7-0 → Gemfile.8-0} +1 -1
- data/Gemfile.8-0.lock +174 -0
- data/Gemfile.lock +1 -1
- data/README.md +69 -100
- data/consul.gemspec +3 -3
- data/lib/consul/active_record.rb +3 -1
- data/lib/consul/util.rb +14 -41
- data/lib/consul/version.rb +1 -1
- data/media/logo.dark.shapes.svg +125 -0
- data/media/logo.dark.text.svg +107 -0
- data/media/logo.light.shapes.svg +89 -0
- data/media/logo.light.text.svg +108 -0
- data/media/makandra-with-bottom-margin.dark.svg +180 -0
- data/media/makandra-with-bottom-margin.light.svg +180 -0
- metadata +21 -16
- data/Gemfile.5-2.lock +0 -128
- data/Gemfile.7-0.lock +0 -133
data/Gemfile.8-0.lock
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
consul (2.0.0)
|
|
5
|
+
activerecord (>= 6.0)
|
|
6
|
+
activesupport (>= 6.0)
|
|
7
|
+
edge_rider (>= 0.3.0)
|
|
8
|
+
memoized (>= 1.0.2)
|
|
9
|
+
railties (>= 6.0)
|
|
10
|
+
|
|
11
|
+
GEM
|
|
12
|
+
remote: https://rubygems.org/
|
|
13
|
+
specs:
|
|
14
|
+
actionpack (8.0.1)
|
|
15
|
+
actionview (= 8.0.1)
|
|
16
|
+
activesupport (= 8.0.1)
|
|
17
|
+
nokogiri (>= 1.8.5)
|
|
18
|
+
rack (>= 2.2.4)
|
|
19
|
+
rack-session (>= 1.0.1)
|
|
20
|
+
rack-test (>= 0.6.3)
|
|
21
|
+
rails-dom-testing (~> 2.2)
|
|
22
|
+
rails-html-sanitizer (~> 1.6)
|
|
23
|
+
useragent (~> 0.16)
|
|
24
|
+
actionview (8.0.1)
|
|
25
|
+
activesupport (= 8.0.1)
|
|
26
|
+
builder (~> 3.1)
|
|
27
|
+
erubi (~> 1.11)
|
|
28
|
+
rails-dom-testing (~> 2.2)
|
|
29
|
+
rails-html-sanitizer (~> 1.6)
|
|
30
|
+
activemodel (8.0.1)
|
|
31
|
+
activesupport (= 8.0.1)
|
|
32
|
+
activerecord (8.0.1)
|
|
33
|
+
activemodel (= 8.0.1)
|
|
34
|
+
activesupport (= 8.0.1)
|
|
35
|
+
timeout (>= 0.4.0)
|
|
36
|
+
activesupport (8.0.1)
|
|
37
|
+
base64
|
|
38
|
+
benchmark (>= 0.3)
|
|
39
|
+
bigdecimal
|
|
40
|
+
concurrent-ruby (~> 1.0, >= 1.3.1)
|
|
41
|
+
connection_pool (>= 2.2.5)
|
|
42
|
+
drb
|
|
43
|
+
i18n (>= 1.6, < 2)
|
|
44
|
+
logger (>= 1.4.2)
|
|
45
|
+
minitest (>= 5.1)
|
|
46
|
+
securerandom (>= 0.3)
|
|
47
|
+
tzinfo (~> 2.0, >= 2.0.5)
|
|
48
|
+
uri (>= 0.13.1)
|
|
49
|
+
assignable_values (1.0.0)
|
|
50
|
+
activerecord (>= 2.3)
|
|
51
|
+
base64 (0.2.0)
|
|
52
|
+
benchmark (0.4.0)
|
|
53
|
+
bigdecimal (3.1.8)
|
|
54
|
+
builder (3.3.0)
|
|
55
|
+
concurrent-ruby (1.3.3)
|
|
56
|
+
connection_pool (2.4.1)
|
|
57
|
+
crass (1.0.6)
|
|
58
|
+
database_cleaner (2.0.2)
|
|
59
|
+
database_cleaner-active_record (>= 2, < 3)
|
|
60
|
+
database_cleaner-active_record (2.2.0)
|
|
61
|
+
activerecord (>= 5.a)
|
|
62
|
+
database_cleaner-core (~> 2.0.0)
|
|
63
|
+
database_cleaner-core (2.0.1)
|
|
64
|
+
date (3.4.1)
|
|
65
|
+
diff-lcs (1.5.1)
|
|
66
|
+
drb (2.2.1)
|
|
67
|
+
edge_rider (2.3.0)
|
|
68
|
+
activerecord (>= 3.2)
|
|
69
|
+
erubi (1.13.0)
|
|
70
|
+
gemika (0.8.3)
|
|
71
|
+
i18n (1.14.5)
|
|
72
|
+
concurrent-ruby (~> 1.0)
|
|
73
|
+
io-console (0.8.0)
|
|
74
|
+
irb (1.14.3)
|
|
75
|
+
rdoc (>= 4.0.0)
|
|
76
|
+
reline (>= 0.4.2)
|
|
77
|
+
logger (1.6.1)
|
|
78
|
+
loofah (2.22.0)
|
|
79
|
+
crass (~> 1.0.2)
|
|
80
|
+
nokogiri (>= 1.12.0)
|
|
81
|
+
memoized (1.1.1)
|
|
82
|
+
mini_portile2 (2.8.8)
|
|
83
|
+
minitest (5.24.1)
|
|
84
|
+
nokogiri (1.16.6)
|
|
85
|
+
mini_portile2 (~> 2.8.2)
|
|
86
|
+
racc (~> 1.4)
|
|
87
|
+
psych (5.2.2)
|
|
88
|
+
date
|
|
89
|
+
stringio
|
|
90
|
+
racc (1.8.0)
|
|
91
|
+
rack (3.1.7)
|
|
92
|
+
rack-session (2.0.0)
|
|
93
|
+
rack (>= 3.0.0)
|
|
94
|
+
rack-test (2.1.0)
|
|
95
|
+
rack (>= 1.3)
|
|
96
|
+
rackup (2.2.1)
|
|
97
|
+
rack (>= 3)
|
|
98
|
+
rails-dom-testing (2.2.0)
|
|
99
|
+
activesupport (>= 5.0.0)
|
|
100
|
+
minitest
|
|
101
|
+
nokogiri (>= 1.6)
|
|
102
|
+
rails-html-sanitizer (1.6.0)
|
|
103
|
+
loofah (~> 2.21)
|
|
104
|
+
nokogiri (~> 1.14)
|
|
105
|
+
railties (8.0.1)
|
|
106
|
+
actionpack (= 8.0.1)
|
|
107
|
+
activesupport (= 8.0.1)
|
|
108
|
+
irb (~> 1.13)
|
|
109
|
+
rackup (>= 1.0.0)
|
|
110
|
+
rake (>= 12.2)
|
|
111
|
+
thor (~> 1.0, >= 1.2.2)
|
|
112
|
+
zeitwerk (~> 2.6)
|
|
113
|
+
rake (13.2.1)
|
|
114
|
+
rdoc (6.10.0)
|
|
115
|
+
psych (>= 4.0.0)
|
|
116
|
+
reline (0.6.0)
|
|
117
|
+
io-console (~> 0.5)
|
|
118
|
+
rspec (3.13.0)
|
|
119
|
+
rspec-core (~> 3.13.0)
|
|
120
|
+
rspec-expectations (~> 3.13.0)
|
|
121
|
+
rspec-mocks (~> 3.13.0)
|
|
122
|
+
rspec-core (3.13.0)
|
|
123
|
+
rspec-support (~> 3.13.0)
|
|
124
|
+
rspec-expectations (3.13.1)
|
|
125
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
126
|
+
rspec-support (~> 3.13.0)
|
|
127
|
+
rspec-mocks (3.13.1)
|
|
128
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
129
|
+
rspec-support (~> 3.13.0)
|
|
130
|
+
rspec-rails (6.1.3)
|
|
131
|
+
actionpack (>= 6.1)
|
|
132
|
+
activesupport (>= 6.1)
|
|
133
|
+
railties (>= 6.1)
|
|
134
|
+
rspec-core (~> 3.13)
|
|
135
|
+
rspec-expectations (~> 3.13)
|
|
136
|
+
rspec-mocks (~> 3.13)
|
|
137
|
+
rspec-support (~> 3.13)
|
|
138
|
+
rspec-support (3.13.1)
|
|
139
|
+
rspec_candy (0.5.1)
|
|
140
|
+
rspec
|
|
141
|
+
sneaky-save
|
|
142
|
+
securerandom (0.3.2)
|
|
143
|
+
shoulda-matchers (6.2.0)
|
|
144
|
+
activesupport (>= 5.2.0)
|
|
145
|
+
sneaky-save (0.1.3)
|
|
146
|
+
activerecord (>= 3.2.0)
|
|
147
|
+
sqlite3 (2.4.1)
|
|
148
|
+
mini_portile2 (~> 2.8.0)
|
|
149
|
+
stringio (3.1.2)
|
|
150
|
+
thor (1.3.2)
|
|
151
|
+
timeout (0.4.1)
|
|
152
|
+
tzinfo (2.0.6)
|
|
153
|
+
concurrent-ruby (~> 1.0)
|
|
154
|
+
uri (1.0.2)
|
|
155
|
+
useragent (0.16.10)
|
|
156
|
+
zeitwerk (2.7.1)
|
|
157
|
+
|
|
158
|
+
PLATFORMS
|
|
159
|
+
ruby
|
|
160
|
+
|
|
161
|
+
DEPENDENCIES
|
|
162
|
+
assignable_values
|
|
163
|
+
consul!
|
|
164
|
+
database_cleaner
|
|
165
|
+
gemika (>= 0.8.1)
|
|
166
|
+
railties (~> 8.0)
|
|
167
|
+
rspec
|
|
168
|
+
rspec-rails
|
|
169
|
+
rspec_candy
|
|
170
|
+
shoulda-matchers
|
|
171
|
+
sqlite3
|
|
172
|
+
|
|
173
|
+
BUNDLED WITH
|
|
174
|
+
2.5.15
|
data/Gemfile.lock
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Gemfile.
|
|
1
|
+
Gemfile.8-0.lock
|
data/README.md
CHANGED
|
@@ -1,19 +1,29 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
<p>
|
|
2
|
+
<a href="https://makandra.de/">
|
|
3
|
+
<picture>
|
|
4
|
+
<source media="(prefers-color-scheme: light)" srcset="media/makandra-with-bottom-margin.light.svg">
|
|
5
|
+
<source media="(prefers-color-scheme: dark)" srcset="media/makandra-with-bottom-margin.dark.svg">
|
|
6
|
+
<img align="right" width="25%" alt="makandra" src="media/makandra-with-bottom-margin.light.svg">
|
|
7
|
+
</picture>
|
|
8
|
+
</a>
|
|
9
|
+
|
|
10
|
+
<picture>
|
|
11
|
+
<source media="(prefers-color-scheme: light)" srcset="media/logo.light.shapes.svg">
|
|
12
|
+
<source media="(prefers-color-scheme: dark)" srcset="media/logo.dark.shapes.svg">
|
|
13
|
+
<img width="155" alt="consul" role="heading" aria-level="1" src="media/logo.light.shapes.svg">
|
|
14
|
+
</picture>
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
[](https://github.com/makandra/consul/actions)
|
|
18
|
+
|
|
19
|
+
Consul is an authorization solution for Ruby on Rails where you describe _sets of accessible things_ to control what a user can see or edit.
|
|
8
20
|
|
|
9
21
|
We have used Consul in combination with [assignable_values](https://github.com/makandra/assignable_values) to solve a variety of authorization requirements ranging from boring to bizarre.
|
|
10
22
|
Also see our crash course video: [Solving bizare authorization requirements with Rails](http://bizarre-authorization.talks.makandra.com/).
|
|
11
23
|
|
|
12
|
-
Consul is tested with Rails
|
|
24
|
+
Consul is tested with Rails 6.1, 7.1, 7.2 and 8.0 on Ruby 2.5, 2.7, 3.2, 3.3 (only if supported, for each Ruby/Rails combination). If you need support for Rails 3.2, please use [v0.13.2](https://github.com/makandra/consul/tree/v0.13.2).
|
|
13
25
|
|
|
14
|
-
|
|
15
|
-
Describing access to your application
|
|
16
|
-
-------------------------------------
|
|
26
|
+
## Describing access to your application
|
|
17
27
|
|
|
18
28
|
You describe access to your application by putting a `Power` model into `app/models/power.rb`.
|
|
19
29
|
Inside your `Power` you can talk about what is accessible for the current user, e.g.
|
|
@@ -51,10 +61,8 @@ There are no restrictions on the name or constructor arguments of this class.
|
|
|
51
61
|
|
|
52
62
|
You can deposit all kinds of objects in your power. See the sections below for details.
|
|
53
63
|
|
|
54
|
-
|
|
55
64
|
### Scope powers (relations)
|
|
56
65
|
|
|
57
|
-
|
|
58
66
|
A typical use case in a Rails application is to restrict access to your ActiveRecord models. For example:
|
|
59
67
|
|
|
60
68
|
- Anonymous visitors may only see public posts
|
|
@@ -111,13 +119,10 @@ power.note!(Note.last) # => raises Consul::Powerless unless the given Note is in
|
|
|
111
119
|
|
|
112
120
|
See our crash course video [Solving bizare authorization requirements with Rails](http://bizarre-authorization.talks.makandra.com/) for many different use cases you can cover with this pattern.
|
|
113
121
|
|
|
114
|
-
|
|
115
|
-
|
|
116
122
|
### Defining different powers for different actions
|
|
117
123
|
|
|
118
124
|
If you have different access rights for e.g. viewing or updating posts, simply use different powers:
|
|
119
125
|
|
|
120
|
-
|
|
121
126
|
```rb
|
|
122
127
|
class Power
|
|
123
128
|
...
|
|
@@ -139,8 +144,6 @@ end
|
|
|
139
144
|
|
|
140
145
|
There is also a [shortcut to map different powers to RESTful controller actions](#protect-entry-into-controller-actions).
|
|
141
146
|
|
|
142
|
-
|
|
143
|
-
|
|
144
147
|
### Boolean powers
|
|
145
148
|
|
|
146
149
|
Boolean powers are useful to control access to stuff that doesn't live in the database:
|
|
@@ -164,7 +167,6 @@ power.dashboard? # => true
|
|
|
164
167
|
power.dashboard! # => raises Consul::Powerless unless Power#dashboard? returns true
|
|
165
168
|
```
|
|
166
169
|
|
|
167
|
-
|
|
168
170
|
### Powers that give no access at all
|
|
169
171
|
|
|
170
172
|
Note that there is a difference between having access to an empty list of records, and having no access at all.
|
|
@@ -194,8 +196,6 @@ power.user?(User.last) # => returns false
|
|
|
194
196
|
power.user!(User.last) # => raises Consul::Powerless
|
|
195
197
|
```
|
|
196
198
|
|
|
197
|
-
|
|
198
|
-
|
|
199
199
|
### Powers that only check a given object
|
|
200
200
|
|
|
201
201
|
Sometimes it is not convenient to define powers as a collection or scope (relation).
|
|
@@ -203,7 +203,6 @@ Sometimes you only want to store a method that checks whether a given object is
|
|
|
203
203
|
|
|
204
204
|
To do so, simply define a power that ends in a question mark:
|
|
205
205
|
|
|
206
|
-
|
|
207
206
|
```rb
|
|
208
207
|
class Power
|
|
209
208
|
...
|
|
@@ -223,7 +222,6 @@ power.updatable_post?(Post.last) # return true if the author of the post is @use
|
|
|
223
222
|
power.updatable_post!(Post.last) # raises Consul::Powerless unless the author of the post is @user
|
|
224
223
|
```
|
|
225
224
|
|
|
226
|
-
|
|
227
225
|
### Other types of powers
|
|
228
226
|
|
|
229
227
|
A power can return any type of object. For instance, you often want to return an array:
|
|
@@ -254,7 +252,6 @@ power.assignable_note_state?('published') # => returns false
|
|
|
254
252
|
power.assignable_note_state!('published') # => raises Consul::Powerless
|
|
255
253
|
```
|
|
256
254
|
|
|
257
|
-
|
|
258
255
|
### Defining multiple powers at once
|
|
259
256
|
|
|
260
257
|
You can define multiple powers at once by giving multiple power names:
|
|
@@ -270,7 +267,6 @@ class Power
|
|
|
270
267
|
end
|
|
271
268
|
```
|
|
272
269
|
|
|
273
|
-
|
|
274
270
|
### Powers that require context (arguments)
|
|
275
271
|
|
|
276
272
|
Sometimes it can be useful to define powers that require context. To do so, just take an argument in your `power` block:
|
|
@@ -294,7 +290,6 @@ note = ...
|
|
|
294
290
|
Power.current.client_note?(client, note)
|
|
295
291
|
```
|
|
296
292
|
|
|
297
|
-
|
|
298
293
|
### Optimizing record checks for scope powers
|
|
299
294
|
|
|
300
295
|
You can query a scope power for a given record, e.g.
|
|
@@ -337,9 +332,7 @@ end
|
|
|
337
332
|
|
|
338
333
|
This way you do not need to touch the database at all.
|
|
339
334
|
|
|
340
|
-
|
|
341
|
-
Role-based permissions
|
|
342
|
-
----------------------
|
|
335
|
+
## Role-based permissions
|
|
343
336
|
|
|
344
337
|
Consul has no built-in support for role-based permissions, but you can easily implement it yourself. Let's say your `User` model has a string column `role` which can be `"author"` or `"admin"`:
|
|
345
338
|
|
|
@@ -367,9 +360,7 @@ class Power
|
|
|
367
360
|
end
|
|
368
361
|
```
|
|
369
362
|
|
|
370
|
-
|
|
371
|
-
Controller integration
|
|
372
|
-
----------------------
|
|
363
|
+
## Controller integration
|
|
373
364
|
|
|
374
365
|
It is convenient to expose the power for the current request to the rest of the application. Consul will help you with that if you tell it how to instantiate a power for the current request:
|
|
375
366
|
|
|
@@ -398,7 +389,6 @@ class NotesController < ApplicationController
|
|
|
398
389
|
end
|
|
399
390
|
```
|
|
400
391
|
|
|
401
|
-
|
|
402
392
|
### Protect entry into controller actions
|
|
403
393
|
|
|
404
394
|
To make sure a power is given before every action in a controller:
|
|
@@ -409,7 +399,7 @@ class NotesController < ApplicationController
|
|
|
409
399
|
end
|
|
410
400
|
```
|
|
411
401
|
|
|
412
|
-
You can use `:except` and `:only` options like in
|
|
402
|
+
You can use `:except` and `:only` options like in before_actions.
|
|
413
403
|
|
|
414
404
|
You can also map different powers to different actions:
|
|
415
405
|
|
|
@@ -441,7 +431,6 @@ class NotesController < ApplicationController
|
|
|
441
431
|
end
|
|
442
432
|
```
|
|
443
433
|
|
|
444
|
-
|
|
445
434
|
And if your power [requires context](#powers-that-require-context-arguments) (is parametrized), you can give it using the `:context` method:
|
|
446
435
|
|
|
447
436
|
```rb
|
|
@@ -458,8 +447,6 @@ class ClientNotesController < ApplicationController
|
|
|
458
447
|
end
|
|
459
448
|
```
|
|
460
449
|
|
|
461
|
-
|
|
462
|
-
|
|
463
450
|
### Auto-mapping a power scope to a controller method
|
|
464
451
|
|
|
465
452
|
It is often convenient to map a power scope to a private controller method:
|
|
@@ -486,7 +473,7 @@ class NotesController < ApplicationController
|
|
|
486
473
|
power :notes, :as => :note_scope
|
|
487
474
|
|
|
488
475
|
# ...
|
|
489
|
-
|
|
476
|
+
|
|
490
477
|
def note_scope
|
|
491
478
|
super.where(trashed: false)
|
|
492
479
|
end
|
|
@@ -494,7 +481,6 @@ class NotesController < ApplicationController
|
|
|
494
481
|
end
|
|
495
482
|
```
|
|
496
483
|
|
|
497
|
-
|
|
498
484
|
### Multiple power-mappings for nested resources
|
|
499
485
|
|
|
500
486
|
When using [nested resources](http://guides.rubyonrails.org/routing.html#nested-resources) you probably want two power
|
|
@@ -564,7 +550,7 @@ class ApplicationController < ActionController::Base
|
|
|
564
550
|
end
|
|
565
551
|
```
|
|
566
552
|
|
|
567
|
-
Note that this check is satisfied by
|
|
553
|
+
Note that this check is satisfied by _any_ `.power` directive in the controller class or its ancestors, even if that `.power` directive has `:only` or `:except` options that do not apply to the current action.
|
|
568
554
|
|
|
569
555
|
Should you want to forego the power check (e.g. to remove authorization checks from an entirely public controller):
|
|
570
556
|
|
|
@@ -574,9 +560,7 @@ class ApiController < ApplicationController
|
|
|
574
560
|
end
|
|
575
561
|
```
|
|
576
562
|
|
|
577
|
-
|
|
578
|
-
Validating assignable values
|
|
579
|
-
----------------------------
|
|
563
|
+
## Validating assignable values
|
|
580
564
|
|
|
581
565
|
Sometimes a scope is not enough to express what a user can edit. You will often want to give a user write access to a record, but restrict the values she can assign to a given field.
|
|
582
566
|
|
|
@@ -647,8 +631,7 @@ The `authorize_values_for` macro comes with many useful options and details best
|
|
|
647
631
|
assignable_values_for :field, :through => lambda { Power.current }
|
|
648
632
|
```
|
|
649
633
|
|
|
650
|
-
Memoization
|
|
651
|
-
-----------
|
|
634
|
+
## Memoization
|
|
652
635
|
|
|
653
636
|
All power methods are [memoized](https://www.justinweiss.com/articles/4-simple-memoization-patterns-in-ruby-and-one-gem/) for performance reasons. Multiple calls to the same method will only call your block the first time, and return a cached result afterwards:
|
|
654
637
|
|
|
@@ -665,9 +648,7 @@ If you want to discard all cached results, call `#unmemoize_all`:
|
|
|
665
648
|
power.unmemoize_all
|
|
666
649
|
```
|
|
667
650
|
|
|
668
|
-
|
|
669
|
-
Dynamic power access
|
|
670
|
-
--------------------
|
|
651
|
+
## Dynamic power access
|
|
671
652
|
|
|
672
653
|
Consul gives you a way to dynamically access and query powers for a given name, model class or record.
|
|
673
654
|
A common use case for this are generic helper methods, e.g. a method to display an "edit" link for any given record
|
|
@@ -687,30 +668,27 @@ end
|
|
|
687
668
|
|
|
688
669
|
You can find a full list of available dynamic calls below:
|
|
689
670
|
|
|
690
|
-
| Dynamic call
|
|
691
|
-
|
|
692
|
-
| `Power.current.send(:notes)`
|
|
693
|
-
| `Power.current.include_power?(:notes)`
|
|
694
|
-
| `Power.current.include_power!(:notes)`
|
|
695
|
-
| `Power.current.include_object?(:notes, Note.last)`
|
|
696
|
-
| `Power.current.include_object!(:notes, Note.last)`
|
|
697
|
-
| `Power.current.for_model(Note)`
|
|
698
|
-
| `Power.current.for_model(:updatable, Note)`
|
|
699
|
-
| `Power.current.include_model?(Note)`
|
|
700
|
-
| `Power.current.include_model?(:updatable, Note)`
|
|
701
|
-
| `Power.current.include_model!(Note)`
|
|
702
|
-
| `Power.current.include_model!(:updatable, Note)`
|
|
703
|
-
| `Power.current.include_record?(Note.last)`
|
|
704
|
-
| `Power.current.include_record?(:updatable, Note.last)`
|
|
705
|
-
| `Power.current.include_record!(Note.last)`
|
|
706
|
-
| `Power.current.include_record!(:updatable, Note.last)`
|
|
707
|
-
| `Power.current.name_for_model(Note)`
|
|
708
|
-
| `Power.current.name_for_model(:updatable, Note)`
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
Querying a power that might be nil
|
|
713
|
-
----------------------------------
|
|
671
|
+
| Dynamic call | Equivalent |
|
|
672
|
+
| ------------------------------------------------------ | ------------------------------------------ |
|
|
673
|
+
| `Power.current.send(:notes)` | `Power.current.notes` |
|
|
674
|
+
| `Power.current.include_power?(:notes)` | `Power.current.notes?` |
|
|
675
|
+
| `Power.current.include_power!(:notes)` | `Power.current.notes!` |
|
|
676
|
+
| `Power.current.include_object?(:notes, Note.last)` | `Power.current.note?(Note.last)` |
|
|
677
|
+
| `Power.current.include_object!(:notes, Note.last)` | `Power.current.note!(Note.last)` |
|
|
678
|
+
| `Power.current.for_model(Note)` | `Power.current.notes` |
|
|
679
|
+
| `Power.current.for_model(:updatable, Note)` | `Power.current.updatable_notes` |
|
|
680
|
+
| `Power.current.include_model?(Note)` | `Power.current.notes?` |
|
|
681
|
+
| `Power.current.include_model?(:updatable, Note)` | `Power.current.updatable_notes?` |
|
|
682
|
+
| `Power.current.include_model!(Note)` | `Power.current.notes!` |
|
|
683
|
+
| `Power.current.include_model!(:updatable, Note)` | `Power.current.updatable_notes!` |
|
|
684
|
+
| `Power.current.include_record?(Note.last)` | `Power.current.note?(Note.last)` |
|
|
685
|
+
| `Power.current.include_record?(:updatable, Note.last)` | `Power.current.updatable_note?(Note.last)` |
|
|
686
|
+
| `Power.current.include_record!(Note.last)` | `Power.current.note!(Note.last)` |
|
|
687
|
+
| `Power.current.include_record!(:updatable, Note.last)` | `Power.current.updatable_note!(Note.last)` |
|
|
688
|
+
| `Power.current.name_for_model(Note)` | `:notes` |
|
|
689
|
+
| `Power.current.name_for_model(:updatable, Note)` | `:updatable_notes` |
|
|
690
|
+
|
|
691
|
+
## Querying a power that might be nil
|
|
714
692
|
|
|
715
693
|
You will often want to access `Power.current` from another model, to e.g. iterate through the list of accessible users:
|
|
716
694
|
|
|
@@ -760,23 +738,20 @@ end
|
|
|
760
738
|
|
|
761
739
|
There is a long selection of class methods that behave neutrally in case `Power.current` is `nil`:
|
|
762
740
|
|
|
763
|
-
| Call
|
|
764
|
-
|
|
765
|
-
| `Power.for_model(Note)`
|
|
766
|
-
| `Power.for_model(:updatable, Note)`
|
|
767
|
-
| `Power.include_model?(Note)`
|
|
768
|
-
| `Power.include_model?(:updatable, Note)`
|
|
769
|
-
| `Power.include_model!(Note)`
|
|
770
|
-
| `Power.include_model!(:updatable, Note)`
|
|
771
|
-
| `Power.include_record?(Note.last)`
|
|
772
|
-
| `Power.include_record?(:updatable, Note.last)`
|
|
773
|
-
| `Power.include_record!(Note.last)`
|
|
774
|
-
| `Power.include_record!(:updatable, Note.last)`
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
Testing
|
|
779
|
-
-------
|
|
741
|
+
| Call | Equivalent |
|
|
742
|
+
| ---------------------------------------------- | ------------------------------------------------------------------- |
|
|
743
|
+
| `Power.for_model(Note)` | `Power.current.present? ? Power.current.notes : Note` |
|
|
744
|
+
| `Power.for_model(:updatable, Note)` | `Power.current.present? ? Power.current.updatable_notes : Note` |
|
|
745
|
+
| `Power.include_model?(Note)` | `Power.current.present? ? Power.notes? : true` |
|
|
746
|
+
| `Power.include_model?(:updatable, Note)` | `Power.current.present? ? Power.updatable_notes? : true` |
|
|
747
|
+
| `Power.include_model!(Note)` | `Power.notes! if Power.current.present?` |
|
|
748
|
+
| `Power.include_model!(:updatable, Note)` | `Power.updatable_notes! if Power.current.present?` |
|
|
749
|
+
| `Power.include_record?(Note.last)` | `Power.current.present? ? Power.note?(Note.last) : true` |
|
|
750
|
+
| `Power.include_record?(:updatable, Note.last)` | `Power.current.present? ? Power.updatable_note?(Note.last?) : true` |
|
|
751
|
+
| `Power.include_record!(Note.last)` | `Power.note!(Note.last) if Power.current.present?` |
|
|
752
|
+
| `Power.include_record!(:updatable, Note.last)` | `Power.updatable_note!(Note.last) if Power.current.present?` |
|
|
753
|
+
|
|
754
|
+
## Testing
|
|
780
755
|
|
|
781
756
|
This section Some hints for testing authorization with Consul.
|
|
782
757
|
|
|
@@ -847,9 +822,7 @@ Power.without_power do
|
|
|
847
822
|
end
|
|
848
823
|
```
|
|
849
824
|
|
|
850
|
-
|
|
851
|
-
Installation
|
|
852
|
-
------------
|
|
825
|
+
## Installation
|
|
853
826
|
|
|
854
827
|
Add the following to your `Gemfile`:
|
|
855
828
|
|
|
@@ -859,15 +832,13 @@ gem 'consul'
|
|
|
859
832
|
|
|
860
833
|
Now run `bundle install` to lock the gem into your project.
|
|
861
834
|
|
|
835
|
+
## Development
|
|
862
836
|
|
|
863
|
-
|
|
864
|
-
-----------
|
|
865
|
-
|
|
866
|
-
We currently develop using Ruby 2.5.3 (see `.ruby-version`) since that version works for current versions of ActiveRecord that we support. GitHub Actions will test additional Ruby versions (2.3.8, 2.4.5, and 3.0.1).
|
|
837
|
+
We currently develop using Ruby 3.4.1 (see `.ruby-version`) since that version works for current versions of ActiveRecord that we support. GitHub Actions will test additional Ruby versions (2.7.3, 3.2.0).
|
|
867
838
|
|
|
868
839
|
There are tests in `spec`. We only accept PRs with tests. To run tests:
|
|
869
840
|
|
|
870
|
-
- Install Ruby
|
|
841
|
+
- Install Ruby 3.4.1
|
|
871
842
|
- run `bundle install`
|
|
872
843
|
- Put your database credentials into `spec/support/database.yml`. There's a `database.sample.yml` you can use as a template.
|
|
873
844
|
- There are gem bundles in the project root for each rails version that we support.
|
|
@@ -884,8 +855,6 @@ Note that we have configured GitHub Actions to automatically run tests in all su
|
|
|
884
855
|
|
|
885
856
|
I'm very eager to keep this gem leightweight and on topic. If you're unsure whether a change would make it into the gem, [talk to me beforehand](mailto:henning.koch@makandra.de).
|
|
886
857
|
|
|
887
|
-
|
|
888
|
-
Credits
|
|
889
|
-
-------
|
|
858
|
+
## Credits
|
|
890
859
|
|
|
891
860
|
Henning Koch from [makandra](http://makandra.com/)
|
data/consul.gemspec
CHANGED
|
@@ -26,8 +26,8 @@ Gem::Specification.new do |s|
|
|
|
26
26
|
s.require_paths = ["lib"]
|
|
27
27
|
|
|
28
28
|
s.add_dependency('memoized', '>=1.0.2')
|
|
29
|
-
s.add_dependency('activerecord', '>=
|
|
30
|
-
s.add_dependency('activesupport', '>=
|
|
31
|
-
s.add_dependency('railties', '>=
|
|
29
|
+
s.add_dependency('activerecord', '>= 6.0')
|
|
30
|
+
s.add_dependency('activesupport', '>= 6.0')
|
|
31
|
+
s.add_dependency('railties', '>= 6.0')
|
|
32
32
|
s.add_dependency('edge_rider', '>= 0.3.0')
|
|
33
33
|
end
|
data/lib/consul/active_record.rb
CHANGED
data/lib/consul/util.rb
CHANGED
|
@@ -3,11 +3,7 @@ module Consul
|
|
|
3
3
|
extend self
|
|
4
4
|
|
|
5
5
|
def scope_selects_all_records?(scope)
|
|
6
|
-
|
|
7
|
-
scope = scope.scoped({})
|
|
8
|
-
else
|
|
9
|
-
scope = scope.scoped
|
|
10
|
-
end
|
|
6
|
+
scope = scope.scoped
|
|
11
7
|
scope_sql = scope.to_sql
|
|
12
8
|
quoted_table_name = Regexp.quote(scope.connection.quote_table_name(scope.table_name))
|
|
13
9
|
all_sql_pattern = /\ASELECT (#{quoted_table_name}\.)?\* FROM #{quoted_table_name}\z/
|
|
@@ -23,26 +19,17 @@ module Consul
|
|
|
23
19
|
end
|
|
24
20
|
|
|
25
21
|
def define_scope(klass, name, lambda)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
klass.
|
|
29
|
-
|
|
30
|
-
klass.send :scope, name, lambda { |*args|
|
|
31
|
-
options = lambda.call(*args)
|
|
32
|
-
klass.scoped(options.slice *EdgeRider::Scoped::VALID_FIND_OPTIONS)
|
|
33
|
-
}
|
|
34
|
-
end
|
|
22
|
+
klass.send :scope, name, lambda { |*args|
|
|
23
|
+
options = lambda.call(*args)
|
|
24
|
+
klass.scoped(options.slice *EdgeRider::Scoped::VALID_FIND_OPTIONS)
|
|
25
|
+
}
|
|
35
26
|
end
|
|
36
27
|
|
|
37
28
|
# This method does not support dynamic default scopes via lambdas
|
|
38
29
|
# (as does #define_scope), because it is currently not required.
|
|
39
30
|
def define_default_scope(klass, conditions)
|
|
40
|
-
|
|
41
|
-
klass.
|
|
42
|
-
else
|
|
43
|
-
klass.send :default_scope do
|
|
44
|
-
klass.scoped(conditions)
|
|
45
|
-
end
|
|
31
|
+
klass.send :default_scope do
|
|
32
|
+
klass.scoped(conditions)
|
|
46
33
|
end
|
|
47
34
|
end
|
|
48
35
|
|
|
@@ -58,33 +45,19 @@ module Consul
|
|
|
58
45
|
end
|
|
59
46
|
|
|
60
47
|
def skip_before_action(controller_class, name, options)
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
# Every `power` in a controller will skip the power check filter. After the 1st time, Rails 5+ will raise
|
|
67
|
-
# an error because there is no `unchecked_power` action to skip any more.
|
|
68
|
-
# To avoid this, we add the following extra option. Note that it must not be added in Rails 4 to avoid errors.
|
|
69
|
-
# See http://api.rubyonrails.org/classes/ActiveSupport/Callbacks/ClassMethods.html#method-i-skip_callback
|
|
70
|
-
controller_class.skip_before_action name, { :raise => false }.merge!(options)
|
|
71
|
-
end
|
|
48
|
+
# Every `power` in a controller will skip the power check filter. After the 1st time, Rails will raise
|
|
49
|
+
# an error because there is no `unchecked_power` action to skip any more.
|
|
50
|
+
# To avoid this, we add the following extra option.
|
|
51
|
+
# See http://api.rubyonrails.org/classes/ActiveSupport/Callbacks/ClassMethods.html#method-i-skip_callback
|
|
52
|
+
controller_class.skip_before_action name, { :raise => false }.merge!(options)
|
|
72
53
|
end
|
|
73
54
|
|
|
74
55
|
def before_action(controller_class, *args, &block)
|
|
75
|
-
|
|
76
|
-
controller_class.before_filter *args, &block
|
|
77
|
-
else
|
|
78
|
-
controller_class.before_action *args, &block
|
|
79
|
-
end
|
|
56
|
+
controller_class.before_action *args, &block
|
|
80
57
|
end
|
|
81
58
|
|
|
82
59
|
def around_action(controller_class, *args, &block)
|
|
83
|
-
|
|
84
|
-
controller_class.around_filter *args, &block
|
|
85
|
-
else
|
|
86
|
-
controller_class.around_action *args, &block
|
|
87
|
-
end
|
|
60
|
+
controller_class.around_action *args, &block
|
|
88
61
|
end
|
|
89
62
|
|
|
90
63
|
end
|
data/lib/consul/version.rb
CHANGED