action_policy 0.2.0 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a261b126090b29222039294b84b4575fa796bf115033c2514fe301e0ec3d34af
4
- data.tar.gz: 05f9d1cd84b2f4ce2b951267e0122fb54a436a5e51f0dd2f9a7d79e06f30d6ec
3
+ metadata.gz: 5aa63f362aa8606be7d0ba77e1c78be9ed8c811eb57b06c38835ec4df24c9bf1
4
+ data.tar.gz: 9c704fda90d4735827eddfb78be38a6f2ea2a293f71165df1955cdd78a3e803d
5
5
  SHA512:
6
- metadata.gz: 80bbbe6ec61bf7241fe0e823844120292e6b8efd98a3c06834d98ac797cf92ebdffa21332e40305770622d5120d391443d0570193001a5e358f1ee6056c09bbb
7
- data.tar.gz: 7f6990f7bcd5998eef536640a451591801afd073e29b25a764c500b1d0f535e3cfaf1a176f0adf930f498386ca9f206aa377b4c5adf1b2d119be642681fa7e81
6
+ metadata.gz: a0cd9a62e04d0dbf1263d5c30ba0e860930877e63dd5c3c93f0be327e204b5e66265b8d9ce264278e9b16bef1bff7924331c66f11f88012c0a26dca445ad51bd
7
+ data.tar.gz: eb7b6b92a10869ab50f71656b446d26199d339891f5336ca28f87918cfd8dad467498e0262011703662944f82c49927e0c26dc24c871c456813ca87397cc4786
@@ -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
@@ -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
@@ -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).
@@ -29,7 +29,8 @@
29
29
  repo: 'https://github.com/palkan/action_policy',
30
30
  loadSidebar: true,
31
31
  subMaxLevel: 3,
32
- ga: 'UA-104346673-3'
32
+ ga: 'UA-104346673-3',
33
+ auto2top:true
33
34
  }
34
35
  </script>
35
36
  <script src="assets/docsify.min.js"></script>
@@ -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 `#{target.class.policy_name}Policy`;
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.
@@ -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 :my_current_user, as: :user
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 :current_user, as: :user
74
+ authorize :user, through: :current_user
75
75
  end
76
76
  ```
77
77
 
@@ -50,7 +50,7 @@ module ActionPolicy
50
50
 
51
51
  @__authorization_context = self.class.authorization_targets
52
52
  .each_with_object({}) do |(key, meth), obj|
53
- obj[key] = public_send(meth)
53
+ obj[key] = send(meth)
54
54
  end
55
55
  end
56
56
 
@@ -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
- app.executor.to_run { ActionPolicy::PerThreadCache.clear_all }
49
- app.executor.to_complete { ActionPolicy::PerThreadCache.clear_all }
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|
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActionPolicy
4
- VERSION = "0.2.0"
4
+ VERSION = "0.2.2"
5
5
  end
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.0
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-06-17 00:00:00.000000000 Z
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