action_policy 0.4.3 → 0.5.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (124) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +221 -174
  3. data/LICENSE.txt +1 -1
  4. data/README.md +7 -11
  5. data/lib/.rbnext/2.7/action_policy/behaviours/policy_for.rb +62 -0
  6. data/lib/.rbnext/2.7/action_policy/i18n.rb +56 -0
  7. data/lib/.rbnext/2.7/action_policy/policy/cache.rb +101 -0
  8. data/lib/.rbnext/2.7/action_policy/policy/pre_check.rb +162 -0
  9. data/lib/.rbnext/2.7/action_policy/rspec/be_authorized_to.rb +89 -0
  10. data/lib/.rbnext/2.7/action_policy/rspec/have_authorized_scope.rb +124 -0
  11. data/lib/.rbnext/2.7/action_policy/utils/pretty_print.rb +159 -0
  12. data/lib/.rbnext/3.0/action_policy/behaviour.rb +115 -0
  13. data/lib/.rbnext/3.0/action_policy/behaviours/policy_for.rb +62 -0
  14. data/lib/.rbnext/3.0/action_policy/behaviours/scoping.rb +35 -0
  15. data/lib/.rbnext/3.0/action_policy/behaviours/thread_memoized.rb +59 -0
  16. data/lib/.rbnext/3.0/action_policy/ext/policy_cache_key.rb +72 -0
  17. data/lib/.rbnext/3.0/action_policy/policy/aliases.rb +69 -0
  18. data/lib/.rbnext/3.0/action_policy/policy/authorization.rb +87 -0
  19. data/lib/.rbnext/3.0/action_policy/policy/cache.rb +101 -0
  20. data/lib/.rbnext/3.0/action_policy/policy/core.rb +161 -0
  21. data/lib/.rbnext/3.0/action_policy/policy/defaults.rb +31 -0
  22. data/lib/.rbnext/3.0/action_policy/policy/execution_result.rb +37 -0
  23. data/lib/.rbnext/3.0/action_policy/policy/pre_check.rb +162 -0
  24. data/lib/.rbnext/3.0/action_policy/policy/reasons.rb +212 -0
  25. data/lib/.rbnext/3.0/action_policy/policy/scoping.rb +160 -0
  26. data/lib/.rbnext/3.0/action_policy/rspec/be_authorized_to.rb +89 -0
  27. data/lib/.rbnext/3.0/action_policy/rspec/have_authorized_scope.rb +124 -0
  28. data/lib/.rbnext/3.0/action_policy/utils/pretty_print.rb +159 -0
  29. data/lib/.rbnext/3.0/action_policy/utils/suggest_message.rb +19 -0
  30. data/lib/action_policy.rb +7 -1
  31. data/lib/action_policy/behaviour.rb +22 -16
  32. data/lib/action_policy/behaviours/policy_for.rb +10 -3
  33. data/lib/action_policy/behaviours/scoping.rb +2 -1
  34. data/lib/action_policy/behaviours/thread_memoized.rb +1 -3
  35. data/lib/action_policy/ext/module_namespace.rb +1 -6
  36. data/lib/action_policy/ext/policy_cache_key.rb +10 -30
  37. data/lib/action_policy/ext/{symbol_classify.rb → symbol_camelize.rb} +6 -6
  38. data/lib/action_policy/i18n.rb +1 -1
  39. data/lib/action_policy/lookup_chain.rb +41 -21
  40. data/lib/action_policy/policy/aliases.rb +7 -12
  41. data/lib/action_policy/policy/authorization.rb +8 -7
  42. data/lib/action_policy/policy/cache.rb +11 -17
  43. data/lib/action_policy/policy/core.rb +25 -12
  44. data/lib/action_policy/policy/defaults.rb +3 -9
  45. data/lib/action_policy/policy/execution_result.rb +3 -9
  46. data/lib/action_policy/policy/pre_check.rb +19 -58
  47. data/lib/action_policy/policy/reasons.rb +32 -20
  48. data/lib/action_policy/policy/scoping.rb +5 -6
  49. data/lib/action_policy/rails/controller.rb +6 -1
  50. data/lib/action_policy/rails/ext/active_record.rb +7 -0
  51. data/lib/action_policy/rails/policy/instrumentation.rb +1 -1
  52. data/lib/action_policy/rspec/be_authorized_to.rb +5 -9
  53. data/lib/action_policy/rspec/dsl.rb +3 -3
  54. data/lib/action_policy/rspec/have_authorized_scope.rb +5 -7
  55. data/lib/action_policy/utils/pretty_print.rb +21 -24
  56. data/lib/action_policy/utils/suggest_message.rb +1 -3
  57. data/lib/action_policy/version.rb +1 -1
  58. data/lib/generators/action_policy/install/templates/{application_policy.rb → application_policy.rb.tt} +1 -1
  59. data/lib/generators/action_policy/policy/policy_generator.rb +4 -1
  60. data/lib/generators/action_policy/policy/templates/{policy.rb → policy.rb.tt} +0 -0
  61. data/lib/generators/rspec/templates/{policy_spec.rb → policy_spec.rb.tt} +0 -0
  62. data/lib/generators/test_unit/templates/{policy_test.rb → policy_test.rb.tt} +0 -0
  63. metadata +55 -119
  64. data/.gitattributes +0 -2
  65. data/.github/FUNDING.yml +0 -1
  66. data/.github/ISSUE_TEMPLATE.md +0 -18
  67. data/.github/PULL_REQUEST_TEMPLATE.md +0 -29
  68. data/.gitignore +0 -15
  69. data/.rubocop.yml +0 -54
  70. data/.tidelift.yml +0 -6
  71. data/.travis.yml +0 -31
  72. data/Gemfile +0 -22
  73. data/Rakefile +0 -27
  74. data/action_policy.gemspec +0 -44
  75. data/benchmarks/namespaced_lookup_cache.rb +0 -71
  76. data/bin/console +0 -14
  77. data/bin/setup +0 -8
  78. data/docs/.nojekyll +0 -0
  79. data/docs/CNAME +0 -1
  80. data/docs/README.md +0 -79
  81. data/docs/_sidebar.md +0 -27
  82. data/docs/aliases.md +0 -122
  83. data/docs/assets/docsify-search.js +0 -364
  84. data/docs/assets/docsify.min.js +0 -3
  85. data/docs/assets/fonts/FiraCode-Medium.woff +0 -0
  86. data/docs/assets/fonts/FiraCode-Regular.woff +0 -0
  87. data/docs/assets/images/banner.png +0 -0
  88. data/docs/assets/images/cache.png +0 -0
  89. data/docs/assets/images/cache.svg +0 -70
  90. data/docs/assets/images/layer.png +0 -0
  91. data/docs/assets/images/layer.svg +0 -35
  92. data/docs/assets/prism-ruby.min.js +0 -1
  93. data/docs/assets/styles.css +0 -347
  94. data/docs/assets/vue.min.css +0 -1
  95. data/docs/authorization_context.md +0 -92
  96. data/docs/behaviour.md +0 -113
  97. data/docs/caching.md +0 -291
  98. data/docs/controller_action_aliases.md +0 -109
  99. data/docs/custom_lookup_chain.md +0 -48
  100. data/docs/custom_policy.md +0 -53
  101. data/docs/debugging.md +0 -55
  102. data/docs/decorators.md +0 -27
  103. data/docs/favicon.ico +0 -0
  104. data/docs/graphql.md +0 -302
  105. data/docs/i18n.md +0 -44
  106. data/docs/index.html +0 -43
  107. data/docs/instrumentation.md +0 -84
  108. data/docs/lookup_chain.md +0 -17
  109. data/docs/namespaces.md +0 -77
  110. data/docs/non_rails.md +0 -28
  111. data/docs/pre_checks.md +0 -57
  112. data/docs/pundit_migration.md +0 -80
  113. data/docs/quick_start.md +0 -118
  114. data/docs/rails.md +0 -120
  115. data/docs/reasons.md +0 -120
  116. data/docs/scoping.md +0 -255
  117. data/docs/testing.md +0 -333
  118. data/docs/writing_policies.md +0 -107
  119. data/gemfiles/jruby.gemfile +0 -8
  120. data/gemfiles/rails42.gemfile +0 -9
  121. data/gemfiles/rails6.gemfile +0 -8
  122. data/gemfiles/railsmaster.gemfile +0 -6
  123. data/lib/action_policy/ext/string_match.rb +0 -14
  124. data/lib/action_policy/ext/yield_self_then.rb +0 -25
@@ -1,291 +0,0 @@
1
- # Caching
2
-
3
- Action Policy aims to be as performant as possible. One of the ways to accomplish that is to include a comprehensive caching system.
4
-
5
- There are several cache layers available: rule-level memoization, local (instance-level) memoization, and _external_ cache (through cache stores).
6
-
7
- <div class="chart-container">
8
- <img src="assets/images/cache.svg" alt="Cache layers" width="60%">
9
- </div>
10
-
11
- ## Policy memoization
12
-
13
- ### Per-instance
14
-
15
- There could be a situation when you need to apply the same policy to the same record multiple times during the action (e.g., request). For example:
16
-
17
- ```ruby
18
- # app/controllers/posts_controller.rb
19
- class PostsController < ApplicationController
20
- def show
21
- @post = Post.find(params[:id])
22
- authorize! @post
23
- render :show
24
- end
25
- end
26
- ```
27
-
28
- ```erb
29
- # app/views/posts/show.html.erb
30
- <h1><%= @post.title %>
31
-
32
- <% if allowed_to?(:edit?, @post) %>
33
- <%= link_to "Edit", @post %>
34
- <% end %>
35
-
36
- <% if allowed_to?(:destroy?, @post) %>
37
- <%= link_to "Delete", @post, method: :delete %>
38
- <% end %>
39
- ```
40
-
41
- In the above example, we need to use the same policy three times. Action Policy re-uses the policy instance to avoid unnecessary object allocation.
42
-
43
- We rely on the following assumptions:
44
- - parent object (e.g., a controller instance) is _ephemeral_, i.e., it is a short-lived object
45
- - all authorizations use the same [authorization context](authorization_context.md).
46
-
47
- We use `record.policy_cache_key` with fallback to `record.cache_key` or `record.object_id` as a part of policy identifier in the local store.
48
-
49
- **NOTE**: policies memoization is an extension for `ActionPolicy::Behaviour` and could be included with `ActionPolicy::Behaviours::Memoized`.
50
-
51
- **NOTE**: memoization is automatically included into Rails controllers integration, but not included into channels integration, since channels are long-lived objects.
52
-
53
- ### Per-thread
54
-
55
- Consider a more complex situation:
56
-
57
- ```ruby
58
- # app/controllers/comments_controller.rb
59
- class CommentsController < ApplicationController
60
- def index
61
- # all comments for all posts
62
- @comments = Comment.all
63
- end
64
- end
65
- ```
66
-
67
- ```erb
68
- # app/views/comments/index.html.erb
69
- <% @comments.each do |comment| %>
70
- <li><%= comment.text %>
71
- <% if allowed_to?(:edit?, comment) %>
72
- <%= link_to comment, "Edit" %>
73
- <% end %>
74
- </li>
75
- <% end %>
76
- ```
77
-
78
- ```ruby
79
- # app/policies/comment_policy.rb
80
- class CommentPolicy < ApplicationPolicy
81
- def edit?
82
- user.admin? || (user.id == record.id) ||
83
- allowed_to?(:manage?, record.post)
84
- end
85
- end
86
- ```
87
-
88
- In some cases, we have to initialize **two** policies for each comment: one for the comment itself and one for the comment's post (in the `allowed_to?` call).
89
-
90
- That is an example of a _N+1 authorization_ problem, which in its turn could easily cause a _N+1 query_ problem (if `PostPolicy#manage?` makes database queries). Sounds terrible, doesn't it?
91
-
92
- It is likely that many comments belong to the same post. If so, we can move our memoization one level up and use local thread store.
93
-
94
- Action Policy provides `ActionPolicy::Behaviours::ThreadMemoized` module with this functionality (included into Rails controllers integration by default).
95
-
96
- If you want to add this behavior to your custom authorization-aware class, you should care about cleaning up the thread store manually (by calling `ActionPolicy::PerThreadCache.clear_all`).
97
-
98
- **NOTE:** per-thread cache is disabled by default in test environment (when either `RACK_ENV` or `RAILS_ENV` environment variable is equal to "test").
99
- You can turn it on (or off) by setting:
100
-
101
- ```ruby
102
- ActionPolicy::PerThreadCache.enabled = true # or false to disable
103
- ```
104
-
105
- ## Rule cache
106
-
107
- ### Per-instance
108
-
109
- There could be a situation when the same rule is called multiple times for the same policy instance (for example, when using [aliases](aliases.md)).
110
-
111
- In that case, Action Policy invokes the rule method only once, remembers the result, and returns it immediately for the subsequent calls.
112
-
113
- **NOTE**: rule results memoization is available only if you inherit from `ActionPolicy::Base` or include `ActionPolicy::Policy::CachedApply` into your `ApplicationPolicy`.
114
-
115
- ### Using the cache store
116
-
117
- Some policy rules might be _performance-heavy_, e.g., make complex database queries.
118
-
119
- In that case, it makes sense to cache the rule application result for a long time (not just for the duration of a request).
120
-
121
- Action Policy provides a way to use _cache stores_ for that. You have to explicitly define which rules you want to cache in your policy class. For example:
122
-
123
- ```ruby
124
- class StagePolicy < ApplicationPolicy
125
- # mark show? rule to be cached
126
- cache :show?
127
- # you can also provide store-specific options
128
- # cache :show?, expires_in: 1.hour
129
-
130
- def show?
131
- full_access? ||
132
- user.stage_permissions.where(
133
- stage_id: record.id
134
- ).exists?
135
- end
136
-
137
- private
138
-
139
- def full_access?
140
- !record.funnel.is_private? ||
141
- user.permissions
142
- .where(
143
- funnel_id: record.funnel_id,
144
- full_access: true
145
- ).exists?
146
- end
147
- end
148
- ```
149
-
150
- You must configure a cache store to use this feature:
151
-
152
- ```ruby
153
- ActionPolicy.cache_store = MyCacheStore.new
154
- ```
155
-
156
- Or, in Rails:
157
-
158
- ```ruby
159
- # config/application.rb (or config/environments/<environment>.rb)
160
- Rails.application.configure do |config|
161
- config.action_policy.cache_store = :redis_cache_store
162
- end
163
- ```
164
-
165
- Cache store must provide at least a `#read(key)` and `write(key, value, **options)` methods.
166
-
167
- **NOTE:** cache store also should take care of serialiation/deserialization since the `value` is `ExecutionResult` instance (which contains also some additional information, e.g. failure reasons). Rails cache store supports serialization/deserialization out-of-the-box.
168
-
169
- By default, Action Policy builds a cache key using the following scheme (defined in `#rule_cache_key(rule)` method):
170
-
171
- ```ruby
172
- "#{cache_namespace}/#{context_cache_key}" \
173
- "/#{record.policy_cache_key}/#{policy.class.name}/#{rule}"
174
- ```
175
-
176
- Where `cache_namespace` is equal to `"acp:#{MAJOR_GEM_VERSION}.#{MINOR_GEM_VERSION}"`, and `context_cache_key` is a concatenation of all authorization contexts cache keys (in the same order as they are defined in the policy class).
177
-
178
- If any object does not respond to `#policy_cache_key`, we fallback to `#cache_key` (or `#cache_key_with_version` for modern Rails versions). If `#cache_key` is not defined, an `ArgumentError` is raised.
179
-
180
- **NOTE:** if your `#cache_key` method is performance-heavy (e.g. like the `ActiveRecord::Relation`'s one), we recommend to explicitly define the `#policy_cache_key` method on the corresponding class to avoid unnecessary load. See also [action_policy#55](https://github.com/palkan/action_policy/issues/55).
181
-
182
- You can define your own `rule_cache_key` / `cache_namespace` / `context_cache_key` methods for policy class to override this logic.
183
-
184
- You can also use the `#cache` instance method to cache arbitrary values in you policies:
185
-
186
- ```ruby
187
- class ApplicationPolicy < ActionPolicy::Base
188
- # Suppose that a user has many roles each having an array of permissions
189
- def permissions
190
- cache(user) { user.roles.pluck(:permissions).flatten.uniq }
191
- end
192
-
193
- # You can pass multiple cache key "parts"
194
- def account_permissions(account)
195
- cache(user, account) { user.account_roles.where(account: account).pluck(:permissions).flatten.uniq }
196
- end
197
- end
198
- ```
199
-
200
- **NOTE:** `#cache` method uses the same cache key generation logic as rules caching (described above).
201
-
202
- #### Invalidation
203
-
204
- There no one-size-fits-all solution for invalidation. It highly depends on your business logic.
205
-
206
- **Case \#1**: no invalidation required.
207
-
208
- First of all, you should try to avoid manual invalidation at all. That could be achieved by using elaborate cache keys.
209
-
210
- Let's consider an example.
211
-
212
- Suppose that your users have _roles_ (i.e. `User.belongs_to :role`) and you give access to resources through the `Access` model (i.e. `Resource.has_many :accesses`).
213
-
214
- Then you can do the following:
215
- - Keep tracking the last `Access` added/updated/deleted for resource (e.g. `Access.belongs_to :accessessable, touch: :access_updated_at`)
216
- - Use the following cache keys:
217
-
218
- ```ruby
219
- class User
220
- def policy_cache_key
221
- "user::#{id}::#{role_id}"
222
- end
223
- end
224
-
225
- class Resource
226
- def policy_cache_key
227
- "#{resource.class.name}::#{id}::#{access_updated_at}"
228
- end
229
- end
230
- ```
231
-
232
- **Case \#2**: discarding all cache at once.
233
-
234
- That's pretty easy: just override `cache_namespace` method in your `ApplicationPolicy` with the new value:
235
-
236
- ```ruby
237
- class ApplicationPolicy < ActionPolicy::Base
238
- # It's a good idea to store the changing part in the constant
239
- CACHE_VERSION = "v2".freeze
240
-
241
- # or even from the env variable
242
- # CACHE_VERSION = ENV.fetch("POLICY_CACHE_VERSION", "v2").freeze
243
-
244
- def cache_namespace
245
- "action_policy::#{CACHE_VERSION}"
246
- end
247
- end
248
- ```
249
-
250
- **Case \#3**: discarding some keys.
251
-
252
- That is an alternative approach to _crafting_ cache keys.
253
-
254
- If you have a limited number of places in your application where you update access control,
255
- you can invalidate policies cache manually. If your cache store supports `delete_matched` command (deleting keys using a wildcard), you can try the following:
256
-
257
- ```ruby
258
- class ApplicationPolicy < ActionPolicy::Base
259
- # Define custom cache key generator
260
- def cache_key(rule)
261
- "policy_cache/#{user.id}/#{self.class.name}/#{record.id}/#{rule}"
262
- end
263
- end
264
-
265
- class Access < ApplicationRecord
266
- belongs_to :resource
267
- belongs_to :user
268
-
269
- after_commit :cleanup_policy_cache, on: [:create, :destroy]
270
-
271
- def cleanup_policy_cache
272
- # Clear cache for the corresponding user-record pair
273
- ActionPolicy.cache_store.delete_matched(
274
- "policy_cache/#{user_id}/#{ResourcePolicy.name}/#{resource_id}/*"
275
- )
276
- end
277
- end
278
-
279
- class User < ApplicationRecord
280
- belongs_to :role
281
-
282
- after_commit :cleanup_policy_cache, on: [:update], if: :role_id_changed?
283
-
284
- def cleanup_policy_cache
285
- # Clear all policies cache for user
286
- ActionPolicy.cache_store.delete_matched(
287
- "policy_cache/#{user_id}/*"
288
- )
289
- end
290
- end
291
- ```
@@ -1,109 +0,0 @@
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).
@@ -1,48 +0,0 @@
1
- # Custom Lookup Chain
2
-
3
- Action Policy's lookup chain is just an array of _probes_ (lambdas with a specific interface).
4
-
5
- The lookup process itself is pretty simple:
6
- - Call the first probe;
7
- - Return the result if it is not `nil`;
8
- - Go to the next probe.
9
-
10
- You can override the default chain with your own. For example:
11
-
12
- ```ruby
13
- ActionPolicy::LookupChain.chain = [
14
- # Probe accepts record as the first argument
15
- # and arbitrary options (passed to `authorize!` / `allowed_to?` call)
16
- lambda do |record, **options|
17
- # your custom lookup logic
18
- end
19
- ]
20
- ```
21
-
22
- ## NullPolicy example
23
-
24
- Let's consider a simple example of extending the existing lookup chain with one more probe.
25
-
26
- Suppose that we want to have a fallback policy (policy used when none found for the resource) instead of raising an `ActionPolicy::NotFound` error.
27
-
28
- Let's call this policy a `NullPolicy`:
29
-
30
- ```ruby
31
- class NullPolicy < ActionPolicy::Base
32
- default_rule :any?
33
-
34
- def any?
35
- false
36
- end
37
- end
38
- ```
39
-
40
- Here we use the [default rule](aliases.md#default-rule) to handle any rule applied.
41
-
42
- Now we need to add a simple probe to the end of our lookup chain:
43
-
44
- ```ruby
45
- ActionPolicy::LookupChain.chain << ->(_, _) { NullPolicy }
46
- ```
47
-
48
- That's it!
@@ -1,53 +0,0 @@
1
- # Custom Base Policy
2
-
3
- `ActionPolicy::Base` is a combination of all available policy extensions with the default configuration.
4
-
5
- It looks like this:
6
-
7
-
8
- ```ruby
9
- class ActionPolicy::Base
10
- include ActionPolicy::Policy::Core
11
- include ActionPolicy::Policy::Authorization
12
- include ActionPolicy::Policy::PreCheck
13
- include ActionPolicy::Policy::Reasons
14
- include ActionPolicy::Policy::Aliases
15
- include ActionPolicy::Policy::Scoping
16
- include ActionPolicy::Policy::Cache
17
- include ActionPolicy::Policy::CachedApply
18
- include ActionPolicy::Policy::Defaults
19
-
20
- # ActionPolicy::Policy::Defaults module adds the following
21
-
22
- authorize :user
23
-
24
- default_rule :manage?
25
- alias_rule :new?, to: :create?
26
-
27
- def index?
28
- false
29
- end
30
-
31
- def create?
32
- false
33
- end
34
-
35
- def manage?
36
- false
37
- end
38
- end
39
- ```
40
-
41
-
42
-
43
- You can write your `ApplicationPolicy` from scratch instead of inheriting from `ActionPolicy::Base`
44
- if the defaults above do not fit your needs. The only required component is `ActionPolicy::Policy::Core`:
45
-
46
- ```ruby
47
- # minimal ApplicationPolicy
48
- class ApplicationPolicy
49
- include ActionPolicy::Policy::Core
50
- end
51
- ```
52
-
53
- The `Core` module provides `apply` and `allowed_to?` methods.