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.
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