i_am_i_can 3.0.1 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|