i_am_i_can 3.0.1 → 4.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/.gitignore +1 -0
- data/README.md +236 -174
- data/lib/generators/i_am_i_can/setup_generator.rb +3 -7
- data/lib/generators/i_am_i_can/templates/migrations/i_am_i_can.erb +8 -8
- data/lib/generators/i_am_i_can/templates/models/permission.erb +4 -2
- data/lib/generators/i_am_i_can/templates/models/role.erb +3 -1
- data/lib/generators/i_am_i_can/templates/models/role_group.erb +3 -1
- data/lib/i_am_i_can/configs/config.rb +2 -3
- data/lib/i_am_i_can/configs/configs.rb +1 -7
- data/lib/i_am_i_can/helpers/dynamic.rb +102 -0
- data/lib/i_am_i_can/helpers/result_of.rb +71 -0
- data/lib/i_am_i_can/permission/assignment.rb +12 -60
- data/lib/i_am_i_can/permission/definition.rb +8 -28
- data/lib/i_am_i_can/permission.rb +18 -24
- data/lib/i_am_i_can/resource.rb +24 -19
- data/lib/i_am_i_can/role/assignment.rb +24 -45
- data/lib/i_am_i_can/role/definition.rb +17 -47
- data/lib/i_am_i_can/role.rb +14 -0
- data/lib/i_am_i_can/role_group/assignment.rb +6 -0
- data/lib/i_am_i_can/role_group/definition.rb +25 -0
- data/lib/i_am_i_can/subject/permission_querying.rb +28 -40
- data/lib/i_am_i_can/subject/role_querying.rb +8 -8
- data/lib/i_am_i_can/subject.rb +0 -10
- data/lib/i_am_i_can/support/association_class_methods.rb +43 -0
- data/lib/i_am_i_can/{configurable.rb → support/configurable.rb} +0 -7
- data/lib/i_am_i_can/support/reflection.rb +36 -0
- data/lib/i_am_i_can/version.rb +1 -1
- data/lib/i_am_i_can.rb +33 -16
- metadata +9 -9
- data/Gemfile.lock +0 -121
- data/lib/i_am_i_can/dynamic_generate.rb +0 -95
- data/lib/i_am_i_can/permission/helpers.rb +0 -75
- data/lib/i_am_i_can/permission/p_array.rb +0 -22
- data/lib/i_am_i_can/reflection.rb +0 -25
- data/lib/i_am_i_can/role/helpers.rb +0 -76
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bd4d579c7635be07c436c9d2f76913fdbaf14638
|
4
|
+
data.tar.gz: 4028733df55abde29ef7a4365e538211bf6192cb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 187dad10491e715a62224579b03906d75ae8716e399d4bc73f006eb3a1bf672693120f14b2d9221daab958a6c6aebdb05ec19dbc738a68f8ebafd1ef31ba6bd7
|
7
|
+
data.tar.gz: 8ad7aff9edb8342d472e08dfaf86e2dc63c26f2b5a90efcf491d637c69f9a60248cc1d730385a0c46a1aff1757cf709ee927ae4a252e8fcabc6a3ec795faac53
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -19,7 +19,6 @@ he.is? :admin # role querying => true
|
|
19
19
|
he.is? :someone_else # role querying => false
|
20
20
|
|
21
21
|
# Role Group
|
22
|
-
# role definition and grouping
|
23
22
|
People.have_and_group_roles :dev, :master, :committer, by_name: :team
|
24
23
|
he.becomes_a :master # role assignment
|
25
24
|
he.in_role_group? :team # role group querying => true
|
@@ -48,11 +47,43 @@ he.falls_from :admin
|
|
48
47
|
Roles.which(name: :coder).cannot :fly
|
49
48
|
|
50
49
|
# Get allowed resources:
|
51
|
-
Resource.that_allow(user
|
50
|
+
Resource.that_allow(user, to: :manage) # => ActiveRecord_Relation[]
|
52
51
|
```
|
53
52
|
|
53
|
+
## Table of Content
|
54
|
+
|
55
|
+
1. [Concepts and Overview](#concepts-and-overview)
|
56
|
+
- [In one word](#in-one-word)
|
57
|
+
- [Definition and uniqueness of nouns](#definition-and-uniqueness-of-nouns)
|
58
|
+
- [About role group](#about-role-group)
|
59
|
+
- [Three steps to use this gem](#three-steps-to-use-this-gem)
|
60
|
+
- [Two Concepts of this gem](#two-concepts-of-this-gem)
|
61
|
+
|
62
|
+
2. [Installation And Setup](#installation-and-setup)
|
63
|
+
|
64
|
+
3. [Usage](#usage)
|
65
|
+
- [Config Options](#config-options)
|
66
|
+
- [Methods and helpers](#methods-and-helpers)
|
67
|
+
- [A. Role Definition](#a-role-definition)
|
68
|
+
- [B. Grouping Roles](#b-grouping-roles)
|
69
|
+
- [C. Role Assignment](#c-role-assignment)
|
70
|
+
- [D. Role / Group Querying](#d-role--group-querying)
|
71
|
+
- [E. Permission Definition](#e-permission-definition)
|
72
|
+
- [F. Permission Assignment](#f-permission-assignment)
|
73
|
+
- [G. Permission Querying](#g-permission-querying)
|
74
|
+
- [H. Shortcut Combinations - which_can](#h-shortcut-combinations---which_can)
|
75
|
+
- [I. Resource Querying](#i-resource-querying)
|
76
|
+
- [J. Useful Helpers](#j-useful-helpers)
|
77
|
+
|
54
78
|
## Concepts and Overview
|
55
79
|
|
80
|
+
### In one word:
|
81
|
+
```
|
82
|
+
- role has permissions
|
83
|
+
- subject has the roles
|
84
|
+
> subject has the permissions through the roles.
|
85
|
+
```
|
86
|
+
|
56
87
|
### Definition and uniqueness of nouns
|
57
88
|
|
58
89
|
0. Subject
|
@@ -70,17 +101,9 @@ Resource.that_allow(user).to(:manage) # => Active::Relation
|
|
70
101
|
- Also see wiki [RBAC](https://en.wikipedia.org/wiki/Role-based_access_control)
|
71
102
|
- Uniquely identified by `predicate( + object)` (name),
|
72
103
|
or we can say, `action( + resource)`
|
73
|
-
4. Resource
|
104
|
+
4. Object (Resource)
|
74
105
|
- Polymorphic association with permissions
|
75
106
|
|
76
|
-
|
77
|
-
### In one word:
|
78
|
-
```
|
79
|
-
- role has permissions
|
80
|
-
- subject has the roles
|
81
|
-
> subject has the permissions through the roles.
|
82
|
-
```
|
83
|
-
|
84
107
|
### About role group?
|
85
108
|
```
|
86
109
|
- role group has permissions
|
@@ -89,7 +112,7 @@ Resource.that_allow(user).to(:manage) # => Active::Relation
|
|
89
112
|
> subject has the permissions through the role which is in the group
|
90
113
|
```
|
91
114
|
|
92
|
-
### Three steps
|
115
|
+
### Three steps to use this gem
|
93
116
|
|
94
117
|
1. Querying
|
95
118
|
- Find if the given role is assigned to the subject
|
@@ -100,7 +123,7 @@ Resource.that_allow(user).to(:manage) # => Active::Relation
|
|
100
123
|
- instance methods, like: `user.has_role :admin`
|
101
124
|
3. Definition
|
102
125
|
- the role or permission you want to assign **MUST** be defined before
|
103
|
-
- option :
|
126
|
+
- option :auto_definition (before assignment) you may need in some cases
|
104
127
|
- class methods, like: `UserRoleGroup.have_permission :fly`
|
105
128
|
|
106
129
|
**Definition => Assignment => Querying**
|
@@ -108,7 +131,7 @@ Resource.that_allow(user).to(:manage) # => Active::Relation
|
|
108
131
|
### Two Concepts of this gem
|
109
132
|
|
110
133
|
1. Stored (save in database) TODO
|
111
|
-
2.
|
134
|
+
2. Temporary (save in instance variable) TODO
|
112
135
|
|
113
136
|
[Feature List: needs you](https://github.com/zhandao/i_am_i_can/issues/2)
|
114
137
|
|
@@ -135,7 +158,7 @@ Resource.that_allow(user).to(:manage) # => Active::Relation
|
|
135
158
|
class User
|
136
159
|
has_and_belongs_to_many :stored_roles,
|
137
160
|
join_table: 'users_and_user_roles', foreign_key: 'user_role_id', class_name: 'UserRole', association_foreign_key: 'user_id'
|
138
|
-
|
161
|
+
has_many_temporary_roles
|
139
162
|
acts_as_subject
|
140
163
|
end
|
141
164
|
```
|
@@ -148,123 +171,127 @@ That's all!
|
|
148
171
|
|
149
172
|
## Usage
|
150
173
|
|
151
|
-
###
|
174
|
+
### Config Options
|
152
175
|
|
153
|
-
1.
|
176
|
+
1. auto_definition: Auto definition before assignment if it's set to `true`. defaults to `false`.
|
154
177
|
|
155
|
-
|
178
|
+
2. strict_mode: Raise error when doing wrong definition or assignment if it's
|
179
|
+
set to `true`. defaults to `false`.
|
156
180
|
|
157
|
-
|
181
|
+
3. without_group: Unable `role group` feature if it's set to `true`. defaults to `false`.
|
158
182
|
|
159
|
-
|
183
|
+
4. **relation names**: you can change the names in model declarations, defaults to `stored_roles`, `permissions`, `stored_users` and so on.
|
184
|
+
|
185
|
+
### Methods and helpers
|
160
186
|
|
161
187
|
#### A. [Role Definition](https://github.com/zhandao/i_am_i_can/blob/master/lib/i_am_i_can/role/definition.rb)
|
162
188
|
|
163
|
-
1.
|
164
|
-
2.
|
165
|
-
1.
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
3. helpers:
|
170
|
-
1. `defined_local_roles`
|
171
|
-
2. `defined_stored_roles` & `defined_stored_role_names`
|
172
|
-
3. `defined_roles`
|
173
|
-
|
174
|
-
Methods Explanation:
|
189
|
+
1. caller: Subject Model, like `User`
|
190
|
+
2. method: `have_role`. aliases:
|
191
|
+
1. `have_roles`
|
192
|
+
2. `has_role` & `has_roles`
|
193
|
+
|
194
|
+
Explanation:
|
175
195
|
```ruby
|
176
|
-
# ===
|
177
|
-
|
178
|
-
have_role *names, desc: nil, save: default_save#, which_can: [ ], obj: nil
|
179
|
-
# examples
|
180
|
-
User.have_roles :admin, :master # => 'Role Definition Done' or error message
|
181
|
-
User.defined_stored_roles.keys.count # => 2
|
196
|
+
# === method signature ===
|
197
|
+
have_role *names, which_can: [ ], obj: nil
|
182
198
|
|
183
|
-
# ===
|
184
|
-
#
|
185
|
-
#
|
186
|
-
User.declare_role :coder # => 'Role Definition Done' or error message
|
187
|
-
User.defined_local_roles.keys.count # => 1
|
199
|
+
# === examples ===
|
200
|
+
User.have_roles :admin, :master # => 'Role Definition Done' or error message
|
201
|
+
# is the same as: `UserRole.create([{ name: :admin }, ...])`
|
188
202
|
|
189
|
-
|
203
|
+
# then:
|
204
|
+
UserRole.count # => 2
|
190
205
|
```
|
191
206
|
|
192
207
|
#### B. [Grouping Roles](https://github.com/zhandao/i_am_i_can/blob/master/lib/i_am_i_can/role/definition.rb)
|
193
208
|
|
194
|
-
**
|
195
|
-
1. Role Group must be saved in database currently
|
196
|
-
2. Roles that you're going to group should be defined
|
209
|
+
**Tip:** Roles that you're going to group should be defined
|
197
210
|
|
198
|
-
|
199
|
-
1. Caller: Subject Model, like `User`
|
211
|
+
1. caller: Subject Model, like `User`
|
200
212
|
2. method: `group_roles`. aliases:
|
201
213
|
1. `group_role`
|
202
214
|
2. `groups_role` & `groups_roles`
|
203
215
|
3. shortcut combination method: `have_and_group_roles` (alias `has_and_groups_roles`)
|
204
|
-
it will do: roles definition
|
216
|
+
it will do: roles definition && roles grouping
|
205
217
|
4. helpers:
|
206
|
-
1.
|
207
|
-
|
208
|
-
|
209
|
-
Methods Explanation:
|
218
|
+
1. relation with role (member), defaults to `members`.
|
219
|
+
|
220
|
+
Explanation:
|
210
221
|
```ruby
|
211
|
-
# method signature
|
212
|
-
group_roles *members, by_name:,
|
213
|
-
|
222
|
+
# === method signature ===
|
223
|
+
group_roles *members, by_name:, which_can: [ ], obj: nil
|
224
|
+
|
225
|
+
# === examples ===
|
226
|
+
# 1. normal usage
|
227
|
+
User.have_roles :vip1, :vip2, :vip3
|
228
|
+
User.group_roles :vip1, :vip2, :vip3, by_name: :vip
|
229
|
+
|
230
|
+
# 2. shortcut combination
|
214
231
|
User.have_and_group_roles :vip1, :vip2, :vip3, by_name: :vip
|
215
|
-
|
216
|
-
|
232
|
+
|
233
|
+
UserRoleGroup.count # => 1
|
234
|
+
UserRoleGroup.which(name: :vip).members.names # => %i[vip1 vip2 vip3]
|
217
235
|
```
|
218
236
|
|
219
237
|
#### C. [Role Assignment](https://github.com/zhandao/i_am_i_can/blob/master/lib/i_am_i_can/role/definition.rb)
|
220
238
|
|
221
|
-
1.
|
222
|
-
2.
|
223
|
-
1.
|
224
|
-
1. `is`
|
225
|
-
2. `has_role`
|
226
|
-
3. `role_is`
|
227
|
-
2.
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
239
|
+
1. caller: subject instance, like `User.first`
|
240
|
+
2. assignment by calling:
|
241
|
+
1. `becomes_a`, or it's aliases:
|
242
|
+
1. `is` / `is_a_role` / `is_roles`
|
243
|
+
2. `has_role` / `has_roles`
|
244
|
+
3. `role_is` / `role_are`
|
245
|
+
2. `is_a_temporary`: just like the name, the assignment occurs only
|
246
|
+
in instance variable (will be in the cache).
|
247
|
+
3. cancel assignment by calling:
|
248
|
+
1. `falls_from`, or it's aliases:
|
249
|
+
1. `removes_role`
|
250
|
+
2. `leaves`
|
251
|
+
3. `is_not_a` / `has_not_role` / `has_not_roles`
|
252
|
+
4. `will_not_be`
|
253
|
+
2. `is_not_a_temporary`
|
233
254
|
4. helpers:
|
234
|
-
1.
|
235
|
-
2. `
|
255
|
+
1. relation with stored role, defaults to `stored_roles`.
|
256
|
+
2. `temporary_roles` and `valid_temporary_roles`
|
236
257
|
3. `roles`
|
237
258
|
|
238
|
-
|
259
|
+
Explanation:
|
239
260
|
```ruby
|
240
261
|
he = User.take
|
241
|
-
#
|
262
|
+
# Dont't forget to define roles before assignment
|
263
|
+
User.have_roles :admin, :coder
|
264
|
+
|
265
|
+
# === Stored Assignment ===
|
242
266
|
# method signature
|
243
|
-
becomes_a *roles,
|
267
|
+
becomes_a *roles, which_can: [ ], obj: nil,
|
268
|
+
_d: config.auto_definition,
|
269
|
+
auto_definition: _d || which_can.present?
|
244
270
|
# examples
|
245
|
-
he.becomes_a :admin # => 'Role
|
246
|
-
he.stored_roles
|
271
|
+
he.becomes_a :admin # => 'Role Assignment Done' or error message
|
272
|
+
he.stored_roles # => [<#UserRole id: 1>]
|
247
273
|
|
248
|
-
# ===
|
274
|
+
# === Temporary Assignment ===
|
249
275
|
# signature as `becomes_a`
|
250
276
|
# examples
|
251
|
-
he.
|
252
|
-
he.
|
277
|
+
he.is_a_temporary :coder # => 'Role Assignment Done' or error message
|
278
|
+
he.temporary_roles # => [<#UserRole id: 2>]
|
253
279
|
|
254
280
|
he.roles # => [:admin, :coder]
|
255
281
|
|
256
|
-
# === Cancel ===
|
282
|
+
# === Cancel Assignment ===
|
257
283
|
# method signature
|
258
|
-
falls_from *roles
|
284
|
+
falls_from *roles
|
285
|
+
is_not_a_temporary *roles
|
259
286
|
# examples
|
260
|
-
he.falls_from :admin
|
261
|
-
he.
|
287
|
+
he.falls_from :admin # => 'Role Assignment Done' or error message
|
288
|
+
he.is_not_a_temporary :coder # => 'Role Assignment Done' or error message
|
262
289
|
he.roles # => []
|
263
290
|
```
|
264
291
|
|
265
292
|
#### D. [Role / Group Querying](https://github.com/zhandao/i_am_i_can/blob/master/lib/i_am_i_can/subject/role_querying.rb)
|
266
293
|
|
267
|
-
1.
|
294
|
+
1. caller: subject instance, like `User.first`
|
268
295
|
2. role querying methods:
|
269
296
|
1. `is?` / `is_role?` / `has_role?`
|
270
297
|
2. `isnt?`
|
@@ -280,7 +307,7 @@ he.roles # => []
|
|
280
307
|
all the `?` methods will return `true` or `false`
|
281
308
|
all the `!` bang methods will return `true` or raise `IAmICan::VerificationFailed`
|
282
309
|
|
283
|
-
|
310
|
+
Examples:
|
284
311
|
```ruby
|
285
312
|
he = User.take
|
286
313
|
|
@@ -288,136 +315,95 @@ he.is? :admin
|
|
288
315
|
he.isnt? :admin
|
289
316
|
he.is! :admin
|
290
317
|
|
291
|
-
he.is_every? :admin, :master # return false if he is not a admin or master
|
292
|
-
he.is_one_of! :admin, :master # return true if he is a master or admin
|
318
|
+
he.is_every? :admin, :master # return false if he is not a `admin` or `master`
|
319
|
+
he.is_one_of! :admin, :master # return true if he is a `master` or `admin`
|
293
320
|
|
294
|
-
he.is_in_role_group? :vip # return true if he has
|
321
|
+
he.is_in_role_group? :vip # return true if he has at least one role of the group `vip`
|
295
322
|
```
|
296
323
|
|
297
324
|
#### E. [Permission Definition](https://github.com/zhandao/i_am_i_can/blob/master/lib/i_am_i_can/permission/definition.rb)
|
298
325
|
|
299
|
-
1.
|
300
|
-
2.
|
301
|
-
1.
|
302
|
-
|
303
|
-
2. `has_permission` & `has_permissions`
|
304
|
-
2. save to local variable: `declare_permission`. alias `declare_permissions`
|
305
|
-
3. helpers:
|
306
|
-
1. `defined_local_permissions`
|
307
|
-
2. `defined_stored_permissions`
|
308
|
-
3. `defined_permissions`
|
309
|
-
4. class method: `which(name:)`
|
310
|
-
5. Permission
|
311
|
-
1. class method: `which(pred:, obj:)`
|
312
|
-
2. instance methods: `#pred`, `#obj`, `#name`
|
313
|
-
|
314
|
-
Methods Explanation:
|
315
|
-
```ruby
|
316
|
-
# === Save to DB ===
|
317
|
-
# method signature
|
318
|
-
have_permission *preds, obj: nil, desc: nil, save: default_save
|
319
|
-
# examples
|
320
|
-
UserRole.have_permission :fly # => 'Permission Definition Done' or error message
|
321
|
-
UserRole.defined_stored_permissions.keys.count # => 1
|
322
|
-
UserRoleGroup.have_permissions *%i[read write], obj: Book.find(1) # => 'Permission Definition Done' or error message
|
323
|
-
UserRoleGroup.defined_stored_permissions.keys.count # => 1
|
324
|
-
|
325
|
-
# === Save in Local ===
|
326
|
-
# signature as `have_permission`
|
327
|
-
# examples
|
328
|
-
UserRole.declare_permission :perform, obj: :magic # => 'Permission Definition Done' or error message
|
329
|
-
UserRole.defined_local_permissions.keys.count # => 1
|
326
|
+
1. caller: Role / Role Group Model, like `UserRole` / `UserRoleGroup`
|
327
|
+
2. method: `have_permission`. aliases:
|
328
|
+
1. `have_permissions`
|
329
|
+
2. `has_permission` & `has_permissions`
|
330
330
|
|
331
|
-
|
331
|
+
Explanation:
|
332
|
+
```ruby
|
333
|
+
# === method signature ===
|
334
|
+
have_permission *actions, obj: nil
|
335
|
+
# It is not recommended to pass an array of objects
|
332
336
|
|
333
|
-
# ===
|
334
|
-
UserRole.
|
335
|
-
#
|
336
|
-
UserRole.find_by_name!(:admin)
|
337
|
+
# === examples ===
|
338
|
+
UserRole.have_permission :fly # => 'Permission Definition Done' or error message
|
339
|
+
UserPermission.count # => 1
|
337
340
|
|
338
|
-
#
|
339
|
-
|
340
|
-
p.pred == 'read'
|
341
|
-
p.obj == Book.find(1)
|
342
|
-
p.name == :read_Book_1
|
341
|
+
UserRoleGroup.have_permissions :read, :write, obj: book # => 'Permission Definition Done' or error message
|
342
|
+
UserPermission.count # => 1 + 2
|
343
343
|
```
|
344
344
|
|
345
345
|
#### F. [Permission Assignment](https://github.com/zhandao/i_am_i_can/blob/master/lib/i_am_i_can/permission/assignment.rb)
|
346
346
|
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
347
|
+
1. caller: role / role group instance, like `UserRole.which(name: :admin)`
|
348
|
+
2. assignment by calling `can`. alias `has_permission`
|
349
|
+
3. cancel assignment by calling `cannot`. alias `is_not_allowed_to`
|
350
|
+
4. helpers:
|
351
|
+
1. relation with stored permission, defaults to `permissions`.
|
351
352
|
|
352
|
-
|
353
|
-
|
354
|
-
2. methods:
|
355
|
-
1. save to database: `can`. aliases: `has_permission`
|
356
|
-
2. save to local variable: `temporarily_can`. alias `locally_can`
|
357
|
-
3. cancel assign method: `cannot`. alias `is_not_allowed_to`
|
358
|
-
3. helpers:
|
359
|
-
1. `local_permissions`
|
360
|
-
2. `stored_permissions`
|
361
|
-
3. `permissions`
|
362
|
-
|
363
|
-
Methods Explanation:
|
353
|
+
|
354
|
+
Explanation:
|
364
355
|
```ruby
|
365
356
|
role = UserRole.which(name: :admin)
|
357
|
+
# Dont't forget to define permission before assginment
|
358
|
+
UserRole.have_permission :fly
|
366
359
|
|
367
|
-
# ===
|
360
|
+
# === Assignment ===
|
368
361
|
# method signature
|
369
|
-
can *
|
362
|
+
can *actions, resource: nil, obj: resource,
|
363
|
+
_d: config.auto_definition, auto_definition: _d
|
370
364
|
# examples
|
371
365
|
role.can :fly # => 'Permission Assignment Done' or error message
|
372
|
-
role.
|
373
|
-
|
374
|
-
# === Save in Local
|
375
|
-
# signature as `can`
|
376
|
-
# examples
|
377
|
-
role.temporarily_can :perform, obj: :magic # => 'Permission Assignment Done' or error message
|
378
|
-
role.local_permissions # => [:perform_magic]
|
379
|
-
|
380
|
-
role.permissions.keys.count # => 3
|
366
|
+
role.permissions # => [<#UserPermission id: ..>]
|
381
367
|
```
|
382
368
|
|
383
369
|
#### G. [Permission Querying](https://github.com/zhandao/i_am_i_can/blob/master/lib/i_am_i_can/subject/role_querying.rb)
|
384
370
|
|
385
|
-
1.
|
371
|
+
1. caller:
|
386
372
|
1. subject instance, like `User.find(1)`
|
387
|
-
2. role / role group instance, like `Role.which(name: :master)`
|
388
|
-
|
373
|
+
2. role / role group instance, like `Role.which(name: :master)`
|
374
|
+
(only have `can?` method)
|
389
375
|
2. methods:
|
390
376
|
1. `can?`
|
391
377
|
2. `cannot?`
|
392
378
|
3. `can!`
|
393
379
|
4. `can_each?` & `can_each!`
|
394
380
|
4. `can_one_of!` & `can_one_of!`
|
395
|
-
5. `temporarily_can?`
|
381
|
+
5. `temporarily_can?`
|
396
382
|
6. `stored_can?`
|
397
383
|
7. `group_can?`
|
398
|
-
3. helpers:
|
399
|
-
1. `permissions_of_stored_roles`
|
400
|
-
2. `permissions_of_local_roles`
|
401
|
-
3. `permissions_of_role_groups`
|
402
384
|
|
403
385
|
all the `?` methods will return `true` or `false`
|
404
386
|
all the `!` bang methods will return `true` or raise `IAmICan::InsufficientPermission`
|
405
387
|
|
406
|
-
|
388
|
+
Examples:
|
407
389
|
```ruby
|
408
390
|
he = User.take
|
409
391
|
|
392
|
+
# `perform` is action, and `magic` is object (resource)
|
410
393
|
he.can? :perform, :magic
|
394
|
+
# the same as:
|
395
|
+
he.can? :perform, obj: :magic
|
396
|
+
|
411
397
|
he.cannot? :perform, :magic
|
412
398
|
he.can! :perform, :magic
|
413
399
|
|
414
|
-
he.can_each?
|
415
|
-
he.can_one_of!
|
400
|
+
he.can_each? %i[fly jump] # return false if he can not `fly` or `jump`
|
401
|
+
he.can_one_of! %i[fly jump] # return true if he can `fly` or `jump`
|
416
402
|
```
|
417
403
|
|
418
404
|
#### H. Shortcut Combinations - which_can
|
419
405
|
|
420
|
-
Faster way to assign, define roles and
|
406
|
+
Faster way to assign, define roles and their permissions.
|
421
407
|
You can use it when defining role even assigning role.
|
422
408
|
|
423
409
|
```ruby
|
@@ -427,9 +413,6 @@ You can use it when defining role even assigning role.
|
|
427
413
|
# 2. define & assign the permission to the role
|
428
414
|
User.have_role :coder, which_can: [:perform], obj: :magic
|
429
415
|
UserRole.which(name: :coder).can? :perform, :magic # => true
|
430
|
-
# save in local
|
431
|
-
User.local_role_which(name: :local_role, can: [:perform], obj: :magic)
|
432
|
-
UserRole.new(name: :local_role).temporarily_can? :perform, :magic # => true
|
433
416
|
|
434
417
|
# === use when assigning role ===
|
435
418
|
# it does:
|
@@ -444,7 +427,86 @@ user.can? :read, :book # => true
|
|
444
427
|
|
445
428
|
#### I. Resource Querying
|
446
429
|
|
447
|
-
|
430
|
+
1. caller: Resource Collection or Instance
|
431
|
+
2. scopes:
|
432
|
+
1. `that_allow`
|
433
|
+
|
434
|
+
Explanation:
|
435
|
+
```ruby
|
436
|
+
# === method signature ===
|
437
|
+
scope :that_allow, -> (subject, to:) { }
|
438
|
+
|
439
|
+
# === examples ===
|
440
|
+
Book.that_allow(User.all, to: :read)
|
441
|
+
Book.that_allow(User.last, to: :write)
|
442
|
+
```
|
443
|
+
|
444
|
+
#### J. Useful Helpers
|
445
|
+
|
446
|
+
1. for Subject (e.g. User)
|
447
|
+
|
448
|
+
```ruby
|
449
|
+
# declaration in User
|
450
|
+
has_and_belongs_to_many :identities # stored_roles
|
451
|
+
|
452
|
+
# 1. [scope] with_<stored_roles>
|
453
|
+
# is the same as `includes(:stored_roles)` for avoiding N+1 querying
|
454
|
+
User.with_identities.where(identities: { name: 'teacher' })
|
455
|
+
```
|
456
|
+
|
457
|
+
2. for Role / RoleGroup (e.g. UserRole)
|
458
|
+
|
459
|
+
```ruby
|
460
|
+
# declaration in UserRole
|
461
|
+
has_and_belongs_to_many :related_users
|
462
|
+
has_and_belongs_to_many :related_role_groups
|
463
|
+
has_and_belongs_to_many :permissions
|
464
|
+
|
465
|
+
# 1. [class method] which(name:, **conditions)
|
466
|
+
# the same as `find_by!`
|
467
|
+
UserRole.which(name: :admin)
|
468
|
+
|
469
|
+
# 2. [class method] names
|
470
|
+
UserRole.all.names # => symbol array
|
471
|
+
|
472
|
+
# 3. [class method] <related_*>
|
473
|
+
# returns a ActiveRecord_Relation
|
474
|
+
# for example, to get the users of the role `admin` and `dev`:
|
475
|
+
UserRole.where(name: ['admin', 'dev']).related_users
|
476
|
+
# to get the groups of the role `admin` and `dev`:
|
477
|
+
UserRole.where(name: ['admin', 'dev']).related_role_groups
|
478
|
+
|
479
|
+
# 4. [scope] with_<permissions>
|
480
|
+
# is the same as `includes(:permissions)` for avoiding N+1 querying
|
481
|
+
UserRole.with_permissions.where(permissions: { id: 1 })
|
482
|
+
```
|
483
|
+
|
484
|
+
3. for `Permission` (e.g. UserPermission)
|
485
|
+
|
486
|
+
```ruby
|
487
|
+
# declaration in UserPermission
|
488
|
+
has_and_belongs_to_many :related_roles
|
489
|
+
has_and_belongs_to_many :related_role_groups
|
490
|
+
|
491
|
+
# 1. [class method] which(action:, obj: nil, **conditions)
|
492
|
+
# the same as `find_by!`
|
493
|
+
UserPermission.which(action: :read, obj: Book.first)
|
494
|
+
UserPermission.which(action: :read, obj_type: 'Book', obj_id: 1)
|
495
|
+
|
496
|
+
# 2. [class method] names
|
497
|
+
UserPermission.all.names # => symbol array
|
498
|
+
|
499
|
+
# 3. [class method] <related_*>
|
500
|
+
# returns a ActiveRecord_Relation as above
|
501
|
+
UserPermission.where(..).related_roles
|
502
|
+
UserPermission.where(..).related_role_groups
|
503
|
+
|
504
|
+
# 4. [instance method] name
|
505
|
+
UserPermission.first.name # => :read_Book_1
|
506
|
+
|
507
|
+
# 5. [instance method] obj
|
508
|
+
UserPermission.first.obj # => nil / Book / book / :book
|
509
|
+
```
|
448
510
|
|
449
511
|
## Development
|
450
512
|
|
@@ -26,17 +26,11 @@ module IAmICan
|
|
26
26
|
@ii_opts[:without_group] = true
|
27
27
|
end
|
28
28
|
|
29
|
-
unless yes?('Do yo want it to save role and permission to database by default? y (default) / n')
|
30
|
-
@ii_opts[:default_save] = false
|
31
|
-
end
|
32
|
-
# if @ii_opts[:default_save] != false && yes?('Don\'t you need **local** definition and assignment feature? y / n (default)')
|
33
|
-
# TODO
|
34
|
-
# end
|
35
29
|
if yes?('Do you want it to raise error when you are doing wrong definition or assignment? y / n (default)')
|
36
30
|
@ii_opts[:strict_mode] = true
|
37
31
|
end
|
38
32
|
if yes?('Do you want it to auto define the role/permission which is not defined when assigning to subject? y / n (default)')
|
39
|
-
@ii_opts[:
|
33
|
+
@ii_opts[:auto_definition] = true
|
40
34
|
end
|
41
35
|
end
|
42
36
|
|
@@ -61,6 +55,8 @@ module IAmICan
|
|
61
55
|
| has_and_belongs_to_many :stored_roles,
|
62
56
|
| join_table: '#{subj_role_tb}', foreign_key: '#{role_u}_id', class_name: '#{role_c}', association_foreign_key: '#{name_u}_id'
|
63
57
|
|
|
58
|
+
| has_many_temporary_roles
|
59
|
+
|
|
64
60
|
| acts_as_subject
|
65
61
|
|
|
66
62
|
TIPS
|
@@ -1,8 +1,8 @@
|
|
1
1
|
class <%= name_c %>Am<%= name_c %>Can < ActiveRecord::Migration::Current
|
2
2
|
def change
|
3
3
|
create_table :<%= role_up %>, force: :cascade do |t|
|
4
|
-
t.string :name,
|
5
|
-
t.string :
|
4
|
+
t.string :name, null: false
|
5
|
+
t.string :remarks
|
6
6
|
|
7
7
|
t.timestamps
|
8
8
|
end
|
@@ -12,8 +12,8 @@ class <%= name_c %>Am<%= name_c %>Can < ActiveRecord::Migration::Current
|
|
12
12
|
# === end of role table ===
|
13
13
|
<% unless @ii_opts[:without_group] %>
|
14
14
|
create_table :<%= group_up %>, force: :cascade do |t|
|
15
|
-
t.string :name,
|
16
|
-
t.string :
|
15
|
+
t.string :name, null: false
|
16
|
+
t.string :remarks
|
17
17
|
|
18
18
|
t.timestamps
|
19
19
|
end
|
@@ -24,17 +24,17 @@ class <%= name_c %>Am<%= name_c %>Can < ActiveRecord::Migration::Current
|
|
24
24
|
|
25
25
|
<% end %>
|
26
26
|
create_table :<%= permission_up %>, force: :cascade do |t|
|
27
|
-
t.string :
|
27
|
+
t.string :action, null: false
|
28
28
|
t.string :obj_type
|
29
29
|
t.integer :obj_id
|
30
|
-
t.string :
|
30
|
+
t.string :remarks
|
31
31
|
|
32
32
|
t.timestamps
|
33
33
|
end
|
34
34
|
|
35
|
-
add_index :<%= permission_up %>, %i[
|
35
|
+
add_index :<%= permission_up %>, %i[ action obj_type obj_id ], unique: true, name: '<%= permission_up %>_unique_index'
|
36
36
|
### Open below if you want to use `Resource.that_allow` frequently
|
37
|
-
# add_index :<%= permission_up %>, %i[
|
37
|
+
# add_index :<%= permission_up %>, %i[ action obj_type ], name: '<%= permission_up %>_resource_search_index'
|
38
38
|
|
39
39
|
# === end of permission table ===
|
40
40
|
|