action_policy 0.4.4 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +203 -174
- data/README.md +5 -4
- data/lib/action_policy.rb +7 -1
- data/lib/action_policy/behaviour.rb +22 -16
- data/lib/action_policy/behaviours/policy_for.rb +10 -3
- data/lib/action_policy/behaviours/scoping.rb +2 -1
- data/lib/action_policy/behaviours/thread_memoized.rb +1 -3
- data/lib/action_policy/ext/module_namespace.rb +1 -6
- data/lib/action_policy/ext/policy_cache_key.rb +10 -30
- data/lib/action_policy/i18n.rb +1 -1
- data/lib/action_policy/lookup_chain.rb +29 -15
- data/lib/action_policy/policy/aliases.rb +7 -12
- data/lib/action_policy/policy/authorization.rb +8 -7
- data/lib/action_policy/policy/cache.rb +11 -17
- data/lib/action_policy/policy/core.rb +25 -12
- data/lib/action_policy/policy/defaults.rb +3 -9
- data/lib/action_policy/policy/execution_result.rb +3 -9
- data/lib/action_policy/policy/pre_check.rb +19 -58
- data/lib/action_policy/policy/reasons.rb +29 -19
- data/lib/action_policy/policy/scoping.rb +5 -6
- data/lib/action_policy/rails/controller.rb +6 -1
- data/lib/action_policy/rails/policy/instrumentation.rb +1 -1
- data/lib/action_policy/rspec/be_authorized_to.rb +5 -9
- data/lib/action_policy/rspec/dsl.rb +1 -1
- data/lib/action_policy/rspec/have_authorized_scope.rb +5 -7
- data/lib/action_policy/utils/pretty_print.rb +21 -24
- data/lib/action_policy/utils/suggest_message.rb +1 -3
- data/lib/action_policy/version.rb +1 -1
- data/lib/generators/action_policy/install/templates/{application_policy.rb → application_policy.rb.tt} +0 -0
- data/lib/generators/action_policy/policy/policy_generator.rb +4 -1
- data/lib/generators/action_policy/policy/templates/{policy.rb → policy.rb.tt} +0 -0
- data/lib/generators/rspec/templates/{policy_spec.rb → policy_spec.rb.tt} +0 -0
- data/lib/generators/test_unit/templates/{policy_test.rb → policy_test.rb.tt} +0 -0
- metadata +29 -119
- data/.gitattributes +0 -2
- data/.github/ISSUE_TEMPLATE.md +0 -21
- data/.github/PULL_REQUEST_TEMPLATE.md +0 -29
- data/.github/bug_report_template.rb +0 -175
- data/.gitignore +0 -15
- data/.rubocop.yml +0 -54
- data/.tidelift.yml +0 -6
- data/.travis.yml +0 -31
- data/Gemfile +0 -22
- data/Rakefile +0 -27
- data/action_policy.gemspec +0 -44
- data/benchmarks/namespaced_lookup_cache.rb +0 -74
- data/benchmarks/pre_checks.rb +0 -73
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/docs/.nojekyll +0 -0
- data/docs/CNAME +0 -1
- data/docs/README.md +0 -79
- data/docs/_sidebar.md +0 -27
- data/docs/aliases.md +0 -122
- data/docs/assets/docsify-search.js +0 -364
- data/docs/assets/docsify.min.js +0 -3
- data/docs/assets/fonts/FiraCode-Medium.woff +0 -0
- data/docs/assets/fonts/FiraCode-Regular.woff +0 -0
- data/docs/assets/images/banner.png +0 -0
- data/docs/assets/images/cache.png +0 -0
- data/docs/assets/images/cache.svg +0 -70
- data/docs/assets/images/layer.png +0 -0
- data/docs/assets/images/layer.svg +0 -35
- data/docs/assets/prism-ruby.min.js +0 -1
- data/docs/assets/styles.css +0 -347
- data/docs/assets/vue.min.css +0 -1
- data/docs/authorization_context.md +0 -92
- data/docs/behaviour.md +0 -113
- data/docs/caching.md +0 -291
- data/docs/controller_action_aliases.md +0 -109
- data/docs/custom_lookup_chain.md +0 -48
- data/docs/custom_policy.md +0 -53
- data/docs/debugging.md +0 -55
- data/docs/decorators.md +0 -27
- data/docs/favicon.ico +0 -0
- data/docs/graphql.md +0 -302
- data/docs/i18n.md +0 -44
- data/docs/index.html +0 -43
- data/docs/instrumentation.md +0 -84
- data/docs/lookup_chain.md +0 -22
- data/docs/namespaces.md +0 -77
- data/docs/non_rails.md +0 -28
- data/docs/pre_checks.md +0 -57
- data/docs/pundit_migration.md +0 -80
- data/docs/quick_start.md +0 -118
- data/docs/rails.md +0 -120
- data/docs/reasons.md +0 -120
- data/docs/scoping.md +0 -255
- data/docs/testing.md +0 -390
- data/docs/writing_policies.md +0 -107
- data/gemfiles/jruby.gemfile +0 -8
- data/gemfiles/rails42.gemfile +0 -9
- data/gemfiles/rails6.gemfile +0 -8
- data/gemfiles/railsmaster.gemfile +0 -6
- data/lib/action_policy/ext/string_match.rb +0 -14
- data/lib/action_policy/ext/yield_self_then.rb +0 -25
data/docs/testing.md
DELETED
@@ -1,390 +0,0 @@
|
|
1
|
-
# Testing
|
2
|
-
|
3
|
-
Authorization is one of the crucial parts of your application. Hence, it should be thoroughly tested (that is the place where 100% coverage makes sense).
|
4
|
-
|
5
|
-
When you use policies for authorization, it is possible to split testing into two parts:
|
6
|
-
- Test the policy class itself
|
7
|
-
- Test that **the required authorization is performed** within your authorization layer (controller, channel, etc.)
|
8
|
-
- Test that **the required scoping has been applied**.
|
9
|
-
|
10
|
-
## Testing policies
|
11
|
-
|
12
|
-
You can test policies as plain-old Ruby classes, no special tooling is required.
|
13
|
-
|
14
|
-
Consider an RSpec example:
|
15
|
-
|
16
|
-
```ruby
|
17
|
-
describe PostPolicy do
|
18
|
-
let(:user) { build_stubbed(:user) }
|
19
|
-
let(:post) { build_stubbed(:post) }
|
20
|
-
|
21
|
-
let(:policy) { described_class.new(post, user: user) }
|
22
|
-
|
23
|
-
describe "#update?" do
|
24
|
-
subject { policy.apply(:update?) }
|
25
|
-
|
26
|
-
it "returns false when the user is not admin nor author" do
|
27
|
-
is_expected.to eq false
|
28
|
-
end
|
29
|
-
|
30
|
-
context "when the user is admin" do
|
31
|
-
let(:user) { build_stubbed(:user, :admin) }
|
32
|
-
|
33
|
-
it { is_expected.to eq true }
|
34
|
-
end
|
35
|
-
|
36
|
-
context "when the user is an author" do
|
37
|
-
let(:post) { build_stubbed(:post, user: user) }
|
38
|
-
|
39
|
-
it { is_expected.to eq true }
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
```
|
44
|
-
|
45
|
-
### RSpec DSL
|
46
|
-
|
47
|
-
We also provide a simple RSpec DSL which aims to reduce the boilerplate when writing
|
48
|
-
policies specs.
|
49
|
-
|
50
|
-
Example:
|
51
|
-
|
52
|
-
```ruby
|
53
|
-
# Add this to your spec_helper.rb / rails_helper.rb
|
54
|
-
require "action_policy/rspec/dsl"
|
55
|
-
|
56
|
-
describe PostPolicy do
|
57
|
-
let(:user) { build_stubbed :user }
|
58
|
-
# `record` must be defined – it is the authorization target
|
59
|
-
let(:record) { build_stubbed :post, draft: false }
|
60
|
-
|
61
|
-
# `context` is the authorization context
|
62
|
-
let(:context) { {user: user} }
|
63
|
-
|
64
|
-
# `describe_rule` is a combination of
|
65
|
-
# `describe` and `subject { ... }` (returns the result of
|
66
|
-
# applying the rule to the record)
|
67
|
-
describe_rule :show? do
|
68
|
-
# `succeed` is `context` + `specify`, which checks
|
69
|
-
# that the result of application is successful
|
70
|
-
succeed "when post is published"
|
71
|
-
|
72
|
-
# `succeed` is `context` + `specify`, which checks
|
73
|
-
# that the result of application wasn't successful
|
74
|
-
failed "when post is draft" do
|
75
|
-
before { post.draft = false }
|
76
|
-
|
77
|
-
succeed "when user is a manager" do
|
78
|
-
before { user.role = "manager" }
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
```
|
84
|
-
|
85
|
-
If test failed the exception message includes the result and [failure reasons](reasons) (if any):
|
86
|
-
|
87
|
-
```
|
88
|
-
1) PostPolicy#show? when post is draft
|
89
|
-
Failure/Error: ...
|
90
|
-
|
91
|
-
Expected to fail but succeed:
|
92
|
-
<PostPolicy#show?: true (reasons: ...)>
|
93
|
-
```
|
94
|
-
|
95
|
-
If you have [debugging utils](debugging) installed the message also includes the _annotated_
|
96
|
-
source code of the policy rule:
|
97
|
-
|
98
|
-
```
|
99
|
-
1) UserPolicy#manage? when post is draft
|
100
|
-
Failure/Error: ...
|
101
|
-
|
102
|
-
Expected to fail but succeed:
|
103
|
-
<PostPolicy#show?: true (reasons: ...)>
|
104
|
-
↳ user.admin? #=> true
|
105
|
-
OR
|
106
|
-
!record.draft? #=> false
|
107
|
-
```
|
108
|
-
|
109
|
-
**NOTE:** DSL for focusing or skipping examples and groups is also available (e.g. `xdescribe_rule`, `fsucceed`, etc.).
|
110
|
-
|
111
|
-
**NOTE:** the DSL is included only to example with the tag `type: :policy` or in the `spec/policies` folder. If you want to add this DSL to other examples, add `include ActionPolicy::RSpec::PolicyExampleGroup`.
|
112
|
-
|
113
|
-
### Testing scopes
|
114
|
-
|
115
|
-
#### Active Record relation example
|
116
|
-
|
117
|
-
There is no single rule on how to test scopes, 'cause it dependes on the _nature_ of the scope.
|
118
|
-
|
119
|
-
Here's an example of RSpec tests for Active Record scoping rules:
|
120
|
-
|
121
|
-
```ruby
|
122
|
-
describe PostPolicy do
|
123
|
-
describe "relation scope" do
|
124
|
-
let(:user) { build_stubbed :user }
|
125
|
-
let(:context) { {user: user} }
|
126
|
-
|
127
|
-
# Feel free to replace with `before_all` from `test-prof`:
|
128
|
-
# https://test-prof.evilmartians.io/#/before_all
|
129
|
-
before do
|
130
|
-
create(:post, name: "A")
|
131
|
-
create(:post, name: "B", draft: true)
|
132
|
-
end
|
133
|
-
|
134
|
-
let(:target) do
|
135
|
-
# We want to make sure that only the records created
|
136
|
-
# for this test are affected, and they have a deterministic order
|
137
|
-
Post.where(name: %w[A B]).order(name: :asc)
|
138
|
-
end
|
139
|
-
|
140
|
-
subject { policy.apply_scope(target, type: :active_record_relation).pluck(:name) }
|
141
|
-
|
142
|
-
context "as user" do
|
143
|
-
it { is_expected.to eq(%w[A]) }
|
144
|
-
end
|
145
|
-
|
146
|
-
context "as manager" do
|
147
|
-
before { user.update!(role: :manager) }
|
148
|
-
|
149
|
-
it { is_expected.to eq(%w[A B]) }
|
150
|
-
end
|
151
|
-
|
152
|
-
context "as banned user" do
|
153
|
-
before { user.update!(banned: true) }
|
154
|
-
|
155
|
-
it { is_expected.to be_empty }
|
156
|
-
end
|
157
|
-
end
|
158
|
-
end
|
159
|
-
```
|
160
|
-
|
161
|
-
#### Action Controller params example
|
162
|
-
|
163
|
-
Here's an example of RSpec tests for Action Controller parameters scoping rules:
|
164
|
-
|
165
|
-
```ruby
|
166
|
-
describe PostPolicy do
|
167
|
-
describe "params scope" do
|
168
|
-
let(:user) { build_stubbed :user }
|
169
|
-
let(:context) { {user: user} }
|
170
|
-
|
171
|
-
let(:params) { {name: "a", password: "b"} }
|
172
|
-
let(:target) { ActionController::Parameters.new(params) }
|
173
|
-
|
174
|
-
# it's easier to asses the hash representation, not the AC::Params object
|
175
|
-
subject { policy.apply_scope(target, type: :action_controller_params).to_h }
|
176
|
-
|
177
|
-
context "as user" do
|
178
|
-
it { is_expected.to eq({name: "a"}) }
|
179
|
-
end
|
180
|
-
|
181
|
-
context "as manager" do
|
182
|
-
before { user.update!(role: :manager) }
|
183
|
-
|
184
|
-
it { is_expected.to eq({name: "a", password: "b"}) }
|
185
|
-
end
|
186
|
-
end
|
187
|
-
end
|
188
|
-
```
|
189
|
-
|
190
|
-
## Testing authorization
|
191
|
-
|
192
|
-
To test the act of authorization you have to make sure that the `authorize!` method is called with the appropriate arguments.
|
193
|
-
|
194
|
-
Action Policy provides tools for such kind of testing for Minitest and RSpec.
|
195
|
-
|
196
|
-
### Minitest
|
197
|
-
|
198
|
-
Include `ActionPolicy::TestHelper` to your test class and you'll be able to use
|
199
|
-
`assert_authorized_to` assertion:
|
200
|
-
|
201
|
-
```ruby
|
202
|
-
# in your controller
|
203
|
-
class PostsController < ApplicationController
|
204
|
-
def update
|
205
|
-
@post = Post.find(params[:id])
|
206
|
-
authorize! @post
|
207
|
-
if @post.update(post_params)
|
208
|
-
redirect_to @post
|
209
|
-
else
|
210
|
-
render :edit
|
211
|
-
end
|
212
|
-
end
|
213
|
-
end
|
214
|
-
|
215
|
-
# in your test
|
216
|
-
require "action_policy/test_helper"
|
217
|
-
|
218
|
-
class PostsControllerTest < ActionDispatch::IntegrationTest
|
219
|
-
include ActionPolicy::TestHelper
|
220
|
-
|
221
|
-
test "update is authorized" do
|
222
|
-
sign_in users(:john)
|
223
|
-
|
224
|
-
post = posts(:example)
|
225
|
-
|
226
|
-
assert_authorized_to(:update?, post, with: PostPolicy) do
|
227
|
-
patch :update, id: post.id, name: "Bob"
|
228
|
-
end
|
229
|
-
end
|
230
|
-
end
|
231
|
-
```
|
232
|
-
|
233
|
-
You can omit the policy (then it would be inferred from the target):
|
234
|
-
|
235
|
-
```ruby
|
236
|
-
assert_authorized_to(:update?, post) do
|
237
|
-
patch :update, id: post.id, name: "Bob"
|
238
|
-
end
|
239
|
-
```
|
240
|
-
|
241
|
-
### RSpec
|
242
|
-
|
243
|
-
Add the following to your `rails_helper.rb` (or `spec_helper.rb`):
|
244
|
-
|
245
|
-
```ruby
|
246
|
-
require "action_policy/rspec"
|
247
|
-
```
|
248
|
-
|
249
|
-
Now you can use `be_authorized_to` matcher:
|
250
|
-
|
251
|
-
```ruby
|
252
|
-
describe PostsController do
|
253
|
-
subject { patch :update, id: post.id, params: params }
|
254
|
-
|
255
|
-
it "is authorized" do
|
256
|
-
expect { subject }.to be_authorized_to(:update?, post)
|
257
|
-
.with(PostPolicy)
|
258
|
-
end
|
259
|
-
end
|
260
|
-
```
|
261
|
-
|
262
|
-
If you omit `.with(PostPolicy)` then the inferred policy for the target (`post`) would be used.
|
263
|
-
|
264
|
-
RSpec composed matchers are available as target:
|
265
|
-
|
266
|
-
```ruby
|
267
|
-
expect { subject }.to be_authorized_to(:show?, an_instance_of(Post))
|
268
|
-
```
|
269
|
-
|
270
|
-
## Testing scoping
|
271
|
-
|
272
|
-
Action Policy provides a way to test that a correct scoping has been applied during the code execution.
|
273
|
-
|
274
|
-
For example, you can test that in your `#index` action the correct scoping is used:
|
275
|
-
|
276
|
-
```ruby
|
277
|
-
class UsersController < ApplicationController
|
278
|
-
def index
|
279
|
-
@user = authorized(User.all)
|
280
|
-
end
|
281
|
-
end
|
282
|
-
```
|
283
|
-
|
284
|
-
### Minitest
|
285
|
-
|
286
|
-
Include `ActionPolicy::TestHelper` to your test class and you'll be able to use
|
287
|
-
`assert_have_authorized_scope` assertion:
|
288
|
-
|
289
|
-
```ruby
|
290
|
-
# in your test
|
291
|
-
require "action_policy/test_helper"
|
292
|
-
|
293
|
-
class UsersControllerTest < ActionDispatch::IntegrationTest
|
294
|
-
include ActionPolicy::TestHelper
|
295
|
-
|
296
|
-
test "index has authorized scope" do
|
297
|
-
sign_in users(:john)
|
298
|
-
|
299
|
-
assert_have_authorized_scope(type: :active_record_relation, with: UserPolicy) do
|
300
|
-
get :index
|
301
|
-
end
|
302
|
-
end
|
303
|
-
end
|
304
|
-
```
|
305
|
-
|
306
|
-
You can also specify `as` and `scope_options` options.
|
307
|
-
|
308
|
-
**NOTE:** both `type` and `with` params are required.
|
309
|
-
|
310
|
-
It's not possible to test that a scoped has been applied to a particular _target_ but we provide
|
311
|
-
a way to perform additional assertions against the matching target (if the assertion didn't fail):
|
312
|
-
|
313
|
-
```ruby
|
314
|
-
test "index has authorized scope" do
|
315
|
-
sign_in users(:john)
|
316
|
-
|
317
|
-
assert_have_authorized_scope(type: :active_record_relation, with: UserPolicy) do
|
318
|
-
get :index
|
319
|
-
end.with_target do |target|
|
320
|
-
# target is a object passed to `authorized` call
|
321
|
-
assert_equal User.all, target
|
322
|
-
end
|
323
|
-
end
|
324
|
-
```
|
325
|
-
|
326
|
-
### RSpec
|
327
|
-
|
328
|
-
Add the following to your `rails_helper.rb` (or `spec_helper.rb`):
|
329
|
-
|
330
|
-
```ruby
|
331
|
-
require "action_policy/rspec"
|
332
|
-
```
|
333
|
-
|
334
|
-
Now you can use `have_authorized_scope` matcher:
|
335
|
-
|
336
|
-
```ruby
|
337
|
-
describe UsersController do
|
338
|
-
subject { get :index }
|
339
|
-
|
340
|
-
it "has authorized scope" do
|
341
|
-
expect { subject }.to have_authorized_scope(:active_record_relation)
|
342
|
-
.with(PostPolicy)
|
343
|
-
end
|
344
|
-
end
|
345
|
-
```
|
346
|
-
|
347
|
-
You can also add `.as(:named_scope)` and `with_scope_options(options_hash)` options.
|
348
|
-
|
349
|
-
RSpec composed matchers are available as scope options:
|
350
|
-
|
351
|
-
```ruby
|
352
|
-
expect { subject }.to have_authorized_scope(:scope)
|
353
|
-
.with_scope_options(matching(with_deleted: a_falsey_value))
|
354
|
-
```
|
355
|
-
|
356
|
-
You can use the `with_target` modifier to run additional expectations against the matching target (if the matcher didn't fail):
|
357
|
-
|
358
|
-
```ruby
|
359
|
-
expect { subject }.to have_authorized_scope(:scope)
|
360
|
-
.with_scope_options(matching(with_deleted: a_falsey_value))
|
361
|
-
.with_target { |target|
|
362
|
-
expect(target).to eq(User.all)
|
363
|
-
}
|
364
|
-
```
|
365
|
-
|
366
|
-
|
367
|
-
## Testing views
|
368
|
-
|
369
|
-
When you test views that call policies methods as `allowed_to?`, your may have `Missing policy authorization context: user` error.
|
370
|
-
You may need to stub `current_user` to resolve the issue.
|
371
|
-
|
372
|
-
Consider an RSpec example:
|
373
|
-
|
374
|
-
```ruby
|
375
|
-
describe "users/index.html.slim" do
|
376
|
-
let(:user) { build_stubbed :user }
|
377
|
-
let(:users) { create_list(:user, 2) }
|
378
|
-
|
379
|
-
before do
|
380
|
-
allow(controller).to receive(:current_user).and_return(user)
|
381
|
-
|
382
|
-
assign :users, users
|
383
|
-
render
|
384
|
-
end
|
385
|
-
|
386
|
-
describe "displays user#index correctly" do
|
387
|
-
it { expect(rendered).to have_link(users.first.email, href: edit_user_path(users.first)) }
|
388
|
-
end
|
389
|
-
end
|
390
|
-
```
|
data/docs/writing_policies.md
DELETED
@@ -1,107 +0,0 @@
|
|
1
|
-
# Writing Policies
|
2
|
-
|
3
|
-
Policy class contains predicate methods (_rules_) which are used to authorize activities.
|
4
|
-
|
5
|
-
A Policy is instantiated with the target `record` (authorization object) and the [authorization context](authorization_context.md) (by default equals to `user`):
|
6
|
-
|
7
|
-
```ruby
|
8
|
-
class PostPolicy < ActionPolicy::Base
|
9
|
-
def index?
|
10
|
-
# allow everyone to perform "index" activity on posts
|
11
|
-
true
|
12
|
-
end
|
13
|
-
|
14
|
-
def update?
|
15
|
-
# here we can access our context and record
|
16
|
-
user.admin? || (user.id == record.user_id)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
```
|
20
|
-
|
21
|
-
## Initializing policies
|
22
|
-
|
23
|
-
**NOTE**: it is not recommended to manually initialize policy objects and use them directly (one exclusion–[tests](testing.md)). Use [`authorize!` / `allowed_to?` methods](./behaviour.md#authorize) instead.
|
24
|
-
|
25
|
-
To initialize policy object, you should specify target record and context:
|
26
|
-
|
27
|
-
```ruby
|
28
|
-
policy = PostPolicy.new(post, user: user)
|
29
|
-
|
30
|
-
# simply call rule method
|
31
|
-
policy.update?
|
32
|
-
```
|
33
|
-
|
34
|
-
You can omit the first argument (in that case `record` would be `nil`).
|
35
|
-
|
36
|
-
Instead of calling rules directly, it is better to call the `apply` method (which wraps rule method with some useful functionality, such as [caching](caching.md), [pre-checks](pre_checks.md), and [failure reasons tracking](reasons.md)):
|
37
|
-
|
38
|
-
```ruby
|
39
|
-
policy.apply(:update?)
|
40
|
-
```
|
41
|
-
|
42
|
-
## Calling other policies
|
43
|
-
|
44
|
-
Sometimes it is useful to call other resources policies from within a policy. Action Policy provides the `allowed_to?` method as a part of `ActionPolicy::Base`:
|
45
|
-
|
46
|
-
```ruby
|
47
|
-
class CommentPolicy < ApplicationPolicy
|
48
|
-
def update?
|
49
|
-
user.admin? || (user.id == record.id) ||
|
50
|
-
allowed_to?(:update?, record.post)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
```
|
54
|
-
|
55
|
-
You can also specify all the usual options (such as `with`).
|
56
|
-
|
57
|
-
There is also a `check?` method which is just an "alias"\* for `allowed_to?` added for better readability:
|
58
|
-
|
59
|
-
```ruby
|
60
|
-
class PostPolicy < ApplicationPolicy
|
61
|
-
def show?
|
62
|
-
user.admin? || check?(:publicly_visible?)
|
63
|
-
end
|
64
|
-
|
65
|
-
def publicly_visible?
|
66
|
-
# ...
|
67
|
-
end
|
68
|
-
end
|
69
|
-
```
|
70
|
-
|
71
|
-
\* It's not a Ruby _alias_ but a wrapper; we can't use `alias` or `alias_method`, 'cause `allowed_to?` could be extended by some extensions.
|
72
|
-
|
73
|
-
## Identifiers
|
74
|
-
|
75
|
-
Each policy class has an `identifier`, which is by default just an underscored class name:
|
76
|
-
|
77
|
-
```ruby
|
78
|
-
class CommentPolicy < ApplicationPolicy
|
79
|
-
end
|
80
|
-
|
81
|
-
CommentPolicy.identifier #=> :comment
|
82
|
-
```
|
83
|
-
|
84
|
-
For namespaced policies it has a form of:
|
85
|
-
|
86
|
-
```ruby
|
87
|
-
module ActiveAdmin
|
88
|
-
class UserPolicy < ApplicationPolicy
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
ActiveAdmin::UserPolicy.identifier # => :"active_admin/user"
|
93
|
-
```
|
94
|
-
|
95
|
-
You can specify your own identifier:
|
96
|
-
|
97
|
-
```ruby
|
98
|
-
module MyVeryLong
|
99
|
-
class LongLongNamePolicy < ApplicationPolicy
|
100
|
-
self.identifier = :long_name
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
MyVeryLong::LongLongNamePolicy.identifier #=> :long_name
|
105
|
-
```
|
106
|
-
|
107
|
-
Identifiers are required for some modules, such as [failure reasons tracking](reasons.md) and [i18n](i18n.md).
|