action_policy 0.2.0 → 0.2.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/action_policy.gemspec +1 -0
- data/benchmarks/namespaced_lookup_cache.rb +75 -0
- data/docs/_sidebar.md +2 -0
- data/docs/controller_action_aliases.md +109 -0
- data/docs/index.html +2 -1
- data/docs/lookup_chain.md +1 -1
- data/docs/rails.md +2 -2
- data/lib/action_policy/behaviour.rb +1 -1
- data/lib/action_policy/cache_middleware.rb +17 -0
- data/lib/action_policy/lookup_chain.rb +7 -2
- data/lib/action_policy/railtie.rb +7 -2
- data/lib/action_policy/version.rb +1 -1
- metadata +19 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5aa63f362aa8606be7d0ba77e1c78be9ed8c811eb57b06c38835ec4df24c9bf1
|
4
|
+
data.tar.gz: 9c704fda90d4735827eddfb78be38a6f2ea2a293f71165df1955cdd78a3e803d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a0cd9a62e04d0dbf1263d5c30ba0e860930877e63dd5c3c93f0be327e204b5e66265b8d9ce264278e9b16bef1bff7924331c66f11f88012c0a26dca445ad51bd
|
7
|
+
data.tar.gz: eb7b6b92a10869ab50f71656b446d26199d339891f5336ca28f87918cfd8dad467498e0262011703662944f82c49927e0c26dc24c871c456813ca87397cc4786
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
## master
|
2
2
|
|
3
|
+
## 0.2.2 (2018-07-01)
|
4
|
+
|
5
|
+
- [Fix [#29](https://github.com/palkan/action_policy/issues/29)] Fix loading cache middleware. ([@palkan][])
|
6
|
+
|
7
|
+
- Use `send` instead of `public_send` to get the `authorization_context` so that contexts such as
|
8
|
+
`current_user` can be `private` in the controller. ([@brendon][])
|
9
|
+
|
10
|
+
- Fix railtie initialisation for Rails < 5. ([@brendon][])
|
11
|
+
|
12
|
+
## 0.2.1 (yanked)
|
13
|
+
|
3
14
|
## 0.2.0 (2018-06-17)
|
4
15
|
|
5
16
|
- Make `action_policy` JRuby-compatible. ([@palkan][])
|
@@ -45,3 +56,4 @@
|
|
45
56
|
|
46
57
|
[@palkan]: https://github.com/palkan
|
47
58
|
[@ilyasgaraev]: https://github.com/ilyasgaraev
|
59
|
+
[@brendon]: https://github.com/brendon
|
data/action_policy.gemspec
CHANGED
@@ -29,4 +29,5 @@ Gem::Specification.new do |spec|
|
|
29
29
|
spec.add_development_dependency "rspec", "~> 3.3"
|
30
30
|
spec.add_development_dependency "rubocop", "~> 0.56.0"
|
31
31
|
spec.add_development_dependency "rubocop-md", "~> 0.2"
|
32
|
+
spec.add_development_dependency "benchmark-ips", "~> 2.7.0"
|
32
33
|
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
=begin
|
4
|
+
|
5
|
+
This benchmark measures the efficiency of NamespaceCache.
|
6
|
+
|
7
|
+
Run it multiple times with cache on/off to see the results:
|
8
|
+
|
9
|
+
$ bundle exec ruby namespaced_lookup_cache.rb
|
10
|
+
$ bundle exec ruby namespaced_lookup_cache.rb
|
11
|
+
$ NO_CACHE=1 bundle exec ruby namespaced_lookup_cache.rb
|
12
|
+
$ NO_CACHE=1 bundle exec ruby namespaced_lookup_cache.rb
|
13
|
+
|
14
|
+
=end
|
15
|
+
|
16
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
17
|
+
|
18
|
+
require "action_policy"
|
19
|
+
require "benchmark/ips"
|
20
|
+
|
21
|
+
GC.disable
|
22
|
+
|
23
|
+
class A; end
|
24
|
+
|
25
|
+
class B; end
|
26
|
+
|
27
|
+
module X
|
28
|
+
class BPolicy < ActionPolicy::Base; end
|
29
|
+
|
30
|
+
module Y
|
31
|
+
module Z
|
32
|
+
class APolicy < ActionPolicy::Base; end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
a = A.new
|
38
|
+
b = B.new
|
39
|
+
|
40
|
+
if ENV['NO_CACHE']
|
41
|
+
ActionPolicy::LookupChain.namespace_cache_enabled = false
|
42
|
+
end
|
43
|
+
|
44
|
+
Benchmark.ips do |x|
|
45
|
+
x.warmup = 0
|
46
|
+
|
47
|
+
x.report("cache A") do
|
48
|
+
ActionPolicy.lookup(a, namespace: X::Y::Z)
|
49
|
+
end
|
50
|
+
|
51
|
+
x.report("cache B") do
|
52
|
+
ActionPolicy.lookup(b, namespace: X::Y::Z)
|
53
|
+
end
|
54
|
+
|
55
|
+
x.report("no cache A") do
|
56
|
+
ActionPolicy.lookup(a, namespace: X::Y::Z)
|
57
|
+
end
|
58
|
+
|
59
|
+
x.report("no cache B") do
|
60
|
+
ActionPolicy.lookup(b, namespace: X::Y::Z)
|
61
|
+
end
|
62
|
+
|
63
|
+
x.hold! 'temp_results'
|
64
|
+
|
65
|
+
x.compare!
|
66
|
+
end
|
67
|
+
|
68
|
+
=begin
|
69
|
+
|
70
|
+
Comparison:
|
71
|
+
cache B: 178577.4 i/s
|
72
|
+
cache A: 173061.4 i/s - same-ish: difference falls within error
|
73
|
+
no cache A: 97991.7 i/s - same-ish: difference falls within error
|
74
|
+
no cache B: 42505.4 i/s - 4.20x slower
|
75
|
+
=end
|
data/docs/_sidebar.md
CHANGED
@@ -14,6 +14,8 @@
|
|
14
14
|
* [Failure Reasons](reasons.md)
|
15
15
|
* [Instrumentation](instrumentation.md)
|
16
16
|
* [I18n Support](i18n.md)
|
17
|
+
* Tips & Tricks
|
18
|
+
* [Controller Action Aliases](controller_action_aliases.md)
|
17
19
|
* Customize
|
18
20
|
* [Base Policy](custom_policy.md)
|
19
21
|
* [Lookup Chain](custom_lookup_chain.md)
|
@@ -0,0 +1,109 @@
|
|
1
|
+
# Controller Action Aliases
|
2
|
+
|
3
|
+
**This is a feature proposed here: https://github.com/palkan/action_policy/issues/25**
|
4
|
+
|
5
|
+
If you'd like to see this feature implemented, please comment on the issue to show your support.
|
6
|
+
|
7
|
+
## Outline
|
8
|
+
|
9
|
+
Say you have abstracted your `authorize!` call to a controller superclass because your policy can
|
10
|
+
be executed without regard to the record in any of the subclass controllers:
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
class AbstractController < ApplicationController
|
14
|
+
authorize :context
|
15
|
+
before_action :authorize_context
|
16
|
+
|
17
|
+
def context
|
18
|
+
# Some code to get your policy context
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def authorize_context
|
24
|
+
authorize! Context
|
25
|
+
end
|
26
|
+
end
|
27
|
+
```
|
28
|
+
|
29
|
+
Your policy might look like this:
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
class ContextPolicy < ApplicationPolicy
|
33
|
+
authorize :context
|
34
|
+
|
35
|
+
alias_rule :index?, :show?, to: :view?
|
36
|
+
alias_rule :new?, :create?, :update?, :destroy?, to: :edit?
|
37
|
+
|
38
|
+
def view?
|
39
|
+
context.has_permission_to(:view, user)
|
40
|
+
end
|
41
|
+
|
42
|
+
def edit?
|
43
|
+
context.has_permission_to(:edit, user)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
```
|
47
|
+
|
48
|
+
We can safely add aliases for the common REST actions in the policy.
|
49
|
+
|
50
|
+
You may then want to include a concern in your subclass controller(s) that add extra actions to the controller.
|
51
|
+
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
class ConcreteController < AbstractController
|
55
|
+
include AdditionalFunctionalityConcern
|
56
|
+
|
57
|
+
def index
|
58
|
+
# Index Action
|
59
|
+
end
|
60
|
+
|
61
|
+
def new
|
62
|
+
# New Action
|
63
|
+
end
|
64
|
+
|
65
|
+
# etc...
|
66
|
+
end
|
67
|
+
```
|
68
|
+
|
69
|
+
At this point you may be wondering how to tell your abstracted policy that these new methods map to either
|
70
|
+
the `view?` or `edit?` rule. You can currently provide the rule to execute to the `authorize!` method with
|
71
|
+
the `to:` parameter but since our call to `authorize!` is in a superclass it has no idea about our concern.
|
72
|
+
I propose the following controller method:
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
alias_action(*actions, to_rule: rule)
|
76
|
+
```
|
77
|
+
|
78
|
+
Here's an example:
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
module AdditionalFunctionalityConcern
|
82
|
+
extend ActiveSupport::Concern
|
83
|
+
|
84
|
+
included do
|
85
|
+
alias_action [:first_action, :second_action], to_rule: :view?
|
86
|
+
alias_action [:third_action], to_rule: :edit?
|
87
|
+
end
|
88
|
+
|
89
|
+
def first_action
|
90
|
+
# First Action
|
91
|
+
end
|
92
|
+
|
93
|
+
def second_action
|
94
|
+
# Second Action
|
95
|
+
end
|
96
|
+
|
97
|
+
def third_action
|
98
|
+
# Third Action
|
99
|
+
end
|
100
|
+
end
|
101
|
+
```
|
102
|
+
|
103
|
+
When `authorize!` is called in a controller, it will first check the action aliases for a corresponding
|
104
|
+
rule. If one is found, it will execute that rule instead of a rule matching the name of the current action.
|
105
|
+
The rule may point at a concrete rule in the policy, or a rule alias in the policy, it doens't matter, the
|
106
|
+
alias in the policy will be resolved like normal.
|
107
|
+
|
108
|
+
If you'd like to see this feature implemented, please show your support on the
|
109
|
+
[Github Issue](https://github.com/palkan/action_policy/issues/25).
|
data/docs/index.html
CHANGED
data/docs/lookup_chain.md
CHANGED
@@ -4,7 +4,7 @@ Action Policy tries to automatically infer policy class from the target using th
|
|
4
4
|
|
5
5
|
1. If the target responds to `policy_class`, then use it;
|
6
6
|
2. If the target's class responds to `policy_class`, then use it;
|
7
|
-
3. If the target's class responds to `policy_name`, then use
|
7
|
+
3. If the target's class responds to `policy_name`, then use it (the `policy_name` should end with `Policy` as it's not appended automatically);
|
8
8
|
4. Otherwise, use `#{target.class.name}Policy`.
|
9
9
|
|
10
10
|
> \* [Namespaces](namespaces.md) could be also be considered when `namespace` option is set.
|
data/docs/rails.md
CHANGED
@@ -12,7 +12,7 @@ You can turn off this behaviour by setting `config.action_policy.controller_auth
|
|
12
12
|
|
13
13
|
```ruby
|
14
14
|
class ApplicationController < ActionController::Base
|
15
|
-
authorize :
|
15
|
+
authorize :user, through: :my_current_user
|
16
16
|
end
|
17
17
|
```
|
18
18
|
|
@@ -71,7 +71,7 @@ class ApiController < ApplicationController::API
|
|
71
71
|
include ActionPolicy::Controller
|
72
72
|
|
73
73
|
# NOTE: you have to provide authorization context manually as well
|
74
|
-
authorize :
|
74
|
+
authorize :user, through: :current_user
|
75
75
|
end
|
76
76
|
```
|
77
77
|
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActionPolicy # :nodoc:
|
4
|
+
class CacheMiddleware # :nodoc:
|
5
|
+
def initialize(app)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
ActionPolicy::PerThreadCache.clear_all
|
11
|
+
result = @app.call(env)
|
12
|
+
ActionPolicy::PerThreadCache.clear_all
|
13
|
+
|
14
|
+
result
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -15,12 +15,14 @@ module ActionPolicy
|
|
15
15
|
require "action_policy/ext/module_namespace"
|
16
16
|
using ActionPolicy::Ext::ModuleNamespace
|
17
17
|
|
18
|
-
# Cache namespace resolving result for policies
|
18
|
+
# Cache namespace resolving result for policies.
|
19
|
+
# @see benchmarks/namespaced_lookup_cache.rb
|
19
20
|
class NamespaceCache
|
20
21
|
class << self
|
21
22
|
attr_reader :store
|
22
23
|
|
23
24
|
def fetch(namespace, policy)
|
25
|
+
return yield unless LookupChain.namespace_cache_enabled
|
24
26
|
return store[namespace][policy] if store[namespace].key?(policy)
|
25
27
|
store[namespace][policy] ||= yield
|
26
28
|
end
|
@@ -34,7 +36,7 @@ module ActionPolicy
|
|
34
36
|
end
|
35
37
|
|
36
38
|
class << self
|
37
|
-
attr_accessor :chain
|
39
|
+
attr_accessor :chain, :namespace_cache_enabled
|
38
40
|
|
39
41
|
def call(record, **opts)
|
40
42
|
chain.each do |probe|
|
@@ -74,6 +76,9 @@ module ActionPolicy
|
|
74
76
|
end
|
75
77
|
end
|
76
78
|
|
79
|
+
# Enable namespace cache by default
|
80
|
+
self.namespace_cache_enabled = true
|
81
|
+
|
77
82
|
# By self `policy_class` method
|
78
83
|
INSTANCE_POLICY_CLASS = ->(record, _) {
|
79
84
|
record.policy_class if record.respond_to?(:policy_class)
|
@@ -45,8 +45,13 @@ module ActionPolicy # :nodoc:
|
|
45
45
|
config.action_policy = Config
|
46
46
|
|
47
47
|
initializer "action_policy.clear_per_thread_cache" do |app|
|
48
|
-
|
49
|
-
|
48
|
+
if Rails::VERSION::MAJOR >= 5
|
49
|
+
app.executor.to_run { ActionPolicy::PerThreadCache.clear_all }
|
50
|
+
app.executor.to_complete { ActionPolicy::PerThreadCache.clear_all }
|
51
|
+
else
|
52
|
+
require "action_policy/cache_middleware"
|
53
|
+
app_middleware.use ActionPolicy::CacheMiddleware
|
54
|
+
end
|
50
55
|
end
|
51
56
|
|
52
57
|
config.to_prepare do |_app|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: action_policy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vladimir Dementyev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-07-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -94,6 +94,20 @@ dependencies:
|
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0.2'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: benchmark-ips
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 2.7.0
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 2.7.0
|
97
111
|
description: Authorization framework for Ruby/Rails application
|
98
112
|
email:
|
99
113
|
- dementiev.vm@gmail.com
|
@@ -113,6 +127,7 @@ files:
|
|
113
127
|
- README.md
|
114
128
|
- Rakefile
|
115
129
|
- action_policy.gemspec
|
130
|
+
- benchmarks/namespaced_lookup_cache.rb
|
116
131
|
- bin/console
|
117
132
|
- bin/setup
|
118
133
|
- docs/.nojekyll
|
@@ -133,6 +148,7 @@ files:
|
|
133
148
|
- docs/assets/vue.min.css
|
134
149
|
- docs/authorization_context.md
|
135
150
|
- docs/caching.md
|
151
|
+
- docs/controller_action_aliases.md
|
136
152
|
- docs/custom_lookup_chain.md
|
137
153
|
- docs/custom_policy.md
|
138
154
|
- docs/favicon.ico
|
@@ -159,6 +175,7 @@ files:
|
|
159
175
|
- lib/action_policy/behaviours/namespaced.rb
|
160
176
|
- lib/action_policy/behaviours/policy_for.rb
|
161
177
|
- lib/action_policy/behaviours/thread_memoized.rb
|
178
|
+
- lib/action_policy/cache_middleware.rb
|
162
179
|
- lib/action_policy/ext/module_namespace.rb
|
163
180
|
- lib/action_policy/ext/policy_cache_key.rb
|
164
181
|
- lib/action_policy/ext/string_constantize.rb
|