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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/README.md +236 -174
  4. data/lib/generators/i_am_i_can/setup_generator.rb +3 -7
  5. data/lib/generators/i_am_i_can/templates/migrations/i_am_i_can.erb +8 -8
  6. data/lib/generators/i_am_i_can/templates/models/permission.erb +4 -2
  7. data/lib/generators/i_am_i_can/templates/models/role.erb +3 -1
  8. data/lib/generators/i_am_i_can/templates/models/role_group.erb +3 -1
  9. data/lib/i_am_i_can/configs/config.rb +2 -3
  10. data/lib/i_am_i_can/configs/configs.rb +1 -7
  11. data/lib/i_am_i_can/helpers/dynamic.rb +102 -0
  12. data/lib/i_am_i_can/helpers/result_of.rb +71 -0
  13. data/lib/i_am_i_can/permission/assignment.rb +12 -60
  14. data/lib/i_am_i_can/permission/definition.rb +8 -28
  15. data/lib/i_am_i_can/permission.rb +18 -24
  16. data/lib/i_am_i_can/resource.rb +24 -19
  17. data/lib/i_am_i_can/role/assignment.rb +24 -45
  18. data/lib/i_am_i_can/role/definition.rb +17 -47
  19. data/lib/i_am_i_can/role.rb +14 -0
  20. data/lib/i_am_i_can/role_group/assignment.rb +6 -0
  21. data/lib/i_am_i_can/role_group/definition.rb +25 -0
  22. data/lib/i_am_i_can/subject/permission_querying.rb +28 -40
  23. data/lib/i_am_i_can/subject/role_querying.rb +8 -8
  24. data/lib/i_am_i_can/subject.rb +0 -10
  25. data/lib/i_am_i_can/support/association_class_methods.rb +43 -0
  26. data/lib/i_am_i_can/{configurable.rb → support/configurable.rb} +0 -7
  27. data/lib/i_am_i_can/support/reflection.rb +36 -0
  28. data/lib/i_am_i_can/version.rb +1 -1
  29. data/lib/i_am_i_can.rb +33 -16
  30. metadata +9 -9
  31. data/Gemfile.lock +0 -121
  32. data/lib/i_am_i_can/dynamic_generate.rb +0 -95
  33. data/lib/i_am_i_can/permission/helpers.rb +0 -75
  34. data/lib/i_am_i_can/permission/p_array.rb +0 -22
  35. data/lib/i_am_i_can/reflection.rb +0 -25
  36. 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: 56545e764dcd1ae9cae7fc388f12df0db09c7628
4
- data.tar.gz: c8dc0126bdd98e472472cb6a105442979a19ef86
3
+ metadata.gz: bd4d579c7635be07c436c9d2f76913fdbaf14638
4
+ data.tar.gz: 4028733df55abde29ef7a4365e538211bf6192cb
5
5
  SHA512:
6
- metadata.gz: fea3768f4b9d4391cb2fb7b0c2be7dfe7f553ead20e004bfdea97ad1a50366b85eb02ebbf905a9d85b72dab2fe4c344c1db58ba23e67bb71ee2d80bbe0c3ddc2
7
- data.tar.gz: aa61ca4f7801fc754cb9b3516a1168de3779ad5c9a6205eb2f18f52acca4d10d0686d71e4e9907553ac50d54e5e4dc612478b07b8f5bb82903cd12473947d27c
6
+ metadata.gz: 187dad10491e715a62224579b03906d75ae8716e399d4bc73f006eb3a1bf672693120f14b2d9221daab958a6c6aebdb05ec19dbc738a68f8ebafd1ef31ba6bd7
7
+ data.tar.gz: 8ad7aff9edb8342d472e08dfaf86e2dc63c26f2b5a90efcf491d637c69f9a60248cc1d730385a0c46a1aff1757cf709ee927ae4a252e8fcabc6a3ec795faac53
data/.gitignore CHANGED
@@ -13,3 +13,4 @@
13
13
  .rspec_status
14
14
 
15
15
  *.log
16
+ Gemfile.lock
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).to(:manage) # => Active::Relation
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 of this gem
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 :auto_define_before (before assignment) you may need in some cases
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. Local (variable value) TODO
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
- ### Customization
174
+ ### Config Options
152
175
 
153
- 1. association names TODO
176
+ 1. auto_definition: Auto definition before assignment if it's set to `true`. defaults to `false`.
154
177
 
155
- ### Config Options
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
- TODO
181
+ 3. without_group: Unable `role group` feature if it's set to `true`. defaults to `false`.
158
182
 
159
- ### Methods and their Aliases
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. Caller: Subject Model, like `User`
164
- 2. methods:
165
- 1. save to database: `have_role`. aliases:
166
- 1. `have_roles`
167
- 2. `has_role` & `has_roles`
168
- 2. save to local variable: `declare_role`. alias `declare_roles`
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
- # === Save to DB ===
177
- # method signature
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
- # === Save in Local ===
184
- # signature as `have_role`
185
- # examples
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
- User.defined_roles.keys.count # => 3
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
- **Tips:**
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
- Overview:
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 => roles grouping
216
+ it will do: roles definition && roles grouping
205
217
  4. helpers:
206
- 1. `defined_role_groups` & `defined_role_group_names`
207
- 2. `members_of_role_group`
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:, #which_can: [ ], obj: nil
213
- # examples
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
- User.defined_role_group_names # => [:vip]
216
- User.members_of_role_group(:vip) # => %i[vip1 vip2 vip3]
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. Caller: subject instance, like `User.find(1)`
222
- 2. assign methods:
223
- 1. save to database: `becomes_a`. aliases:
224
- 1. `is` & `is_a_role` & `is_roles`
225
- 2. `has_role` & `has_roles`
226
- 3. `role_is` & `role_are`
227
- 2. save to local variable: `temporarily_is`. alias `locally_is`
228
- 3. cancel assign method: `falls_from`. aliases:
229
- 1. `removes_role`
230
- 2. `leaves`
231
- 3. `is_not_a` & `has_not_role` & `has_not_roles`
232
- 4. `will_not_be`
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. `local_roles` & `local_role_names`
235
- 2. `stored_roles` & `stored_role_names`
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
- Methods Explanation:
259
+ Explanation:
239
260
  ```ruby
240
261
  he = User.take
241
- # === Save to DB ===
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, auto_define_before: auto_define_before, save: default_save#, which_can: [ ], obj: nil
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 Definition Done' or error message
246
- he.stored_roles # => [<#UserRole id: 1>]
271
+ he.becomes_a :admin # => 'Role Assignment Done' or error message
272
+ he.stored_roles # => [<#UserRole id: 1>]
247
273
 
248
- # === Save in Local ===
274
+ # === Temporary Assignment ===
249
275
  # signature as `becomes_a`
250
276
  # examples
251
- he.temporarily_is :coder # => 'Role Assignment Done' or error message
252
- he.local_roles # => [{ coder: { .. } }]
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, saved: default_save
284
+ falls_from *roles
285
+ is_not_a_temporary *roles
259
286
  # examples
260
- he.falls_from :admin # => 'Role Assignment Done' or error message
261
- he.removes_roles :coder, saved: false # => 'Role Assignment Done' or error message
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. Caller: subject instance, like `User.find(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
- Methods Examples:
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 a role which is in the group :vip
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. Caller: Role / Role Group Model, like `UserRole` / `UserRoleGroup`
300
- 2. methods:
301
- 1. save to database: `have_permission`. aliases:
302
- 1. `have_permissions`
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
- UserRole.defined_permissions.keys.count # => 2
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
- # === class methods ===
334
- UserRole.which(name: :admin)
335
- # as same as
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
- # === Permission ===
339
- p = UserPermission.which(pred: :read, obj: Book.find(1))
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
- **What is Wrong Assignment - Covered?**
348
- > Before: he can manage User
349
- > When you do: he can manage User.find(1)
350
- > will get an Error, tell you that User is cover User.find(1), no need to assign
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
- Overview:
353
- 1. Caller: role / role group instance, like `UserRole.which(name: :admin)`
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
- # === Save to DB ===
360
+ # === Assignment ===
368
361
  # method signature
369
- can *preds, obj: nil, strict_mode: false, auto_define_before: auto_define_before
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.stored_permissions # => [<#UserPermission id: ..>]
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. Caller:
371
+ 1. caller:
386
372
  1. subject instance, like `User.find(1)`
387
- 2. role / role group instance, like `Role.which(name: :master)`
388
- notice that this caller have only `can?` and `temporarily_can?` methods.
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?` / `locally_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
- Methods Examples:
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? :fly, :jump # return false if he can not fly or jump
415
- he.can_one_of! :fly, :jump # return true if he can fly or jump
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 thier permissions.
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
- TODO
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[:auto_define_before] = true
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, null: false
5
- t.string :desc
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, null: false
16
- t.string :desc
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 :pred, null: false
27
+ t.string :action, null: false
28
28
  t.string :obj_type
29
29
  t.integer :obj_id
30
- t.string :desc
30
+ t.string :remarks
31
31
 
32
32
  t.timestamps
33
33
  end
34
34
 
35
- add_index :<%= permission_up %>, %i[ pred obj_type obj_id ], unique: true, name: '<%= permission_up %>_unique_index'
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[ pred obj_type ], name: '<%= permission_up %>_resource_search_index'
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