troles 0.5.1 → 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Design.textile +68 -0
- data/Gemfile +9 -7
- data/Gemfile.lock +81 -76
- data/README.textile +63 -170
- data/VERSION +1 -1
- data/lib/trole.rb +2 -2
- data/lib/trole_groups/storage/base_many.rb +16 -5
- data/lib/troles/adapters/active_record/config.rb +19 -5
- data/lib/troles/api/config.rb +1 -1
- data/lib/troles/api/core.rb +4 -4
- data/lib/troles/common/api/core.rb +13 -14
- data/lib/troles/common/api/read.rb +6 -0
- data/lib/troles/common/api.rb +3 -2
- data/lib/troles/common/config/schema/helpers.rb +30 -11
- data/lib/troles/common/config/schema/role_helpers.rb +5 -5
- data/lib/troles/common/config/valid_roles.rb +4 -3
- data/lib/troles/common/dependencies.rb +1 -1
- data/lib/troles/common/storage.rb +16 -4
- data/lib/troles/common.rb +2 -2
- data/lib/troles/config.rb +4 -4
- data/lib/troles/storage/join_ref_many.rb +13 -0
- data/lib/troles/storage.rb +6 -5
- data/lib/troles.rb +3 -8
- data/spec/active_record/migrations/many/custom_join.rb +31 -0
- data/spec/active_record/migrations/many/join_ref_many.rb +31 -0
- data/spec/active_record/migrations/many/ref_many.rb +0 -8
- data/spec/active_record/models/custom_join.rb +13 -0
- data/spec/active_record/models/join_ref_many.rb +13 -0
- data/spec/active_record/models/ref_many.rb +0 -2
- data/spec/active_record/strategies/many/custom_join_spec.rb +46 -0
- data/spec/active_record/strategies/many/join_ref_many_spec.rb +46 -0
- data/spec/active_record/strategies/many/ref_many_spec.rb +2 -2
- data/spec/generic/models/base_user.rb +2 -1
- data/spec/trole/strategies/embed_one_spec.rb +1 -1
- data/spec/trole/strategies/ref_one_spec.rb +1 -1
- data/spec/trole/strategies/string_one_spec.rb +1 -1
- data/spec/troles/common/multi_roles_spec.rb +7 -13
- data/spec/troles/strategies/bit_many_spec.rb +1 -1
- data/spec/troles/strategies/embed_many_spec.rb +1 -1
- data/spec/troles/strategies/ref_many_spec.rb +1 -1
- data/spec/troles/strategies/string_many_spec.rb +1 -1
- data/spec/troles/strategy_helper.rb +1 -1
- data/troles.gemspec +38 -24
- metadata +72 -42
data/README.textile
CHANGED
@@ -13,75 +13,6 @@ The roles list cache of a role subject (fx a user) is only updated (retrieved fr
|
|
13
13
|
|
14
14
|
Note: Troles is a full redesign of _roles generic_ and company, using lessons learned. Troles uses a much cleaner design. It is aimed at being easy to extend and easy to create adapters for etc.
|
15
15
|
|
16
|
-
h2. Status June 7, 2011
|
17
|
-
|
18
|
-
I'm now in the process of implementing TroleGroups! Finally a fully integrated role groups solution for Ruby and Rails ;)
|
19
|
-
Due to the flexible design ot troles and trole, I can reuse the same infrastructure/design/architecture to implement trole_groups!
|
20
|
-
*Yiii...haaa!*
|
21
|
-
|
22
|
-
"A RoleGroup is simply another role_subject and can thus be configured with a given role strategy!"
|
23
|
-
|
24
|
-
Simple and Sweet :)
|
25
|
-
|
26
|
-
h2. The Ruby Class Decorator (RCD) pattern is born!!!
|
27
|
-
|
28
|
-
I realized a while ago that I had come upon a very cool kind of "class decorator" design pattern that can be generalized to any gem that "decorates" a class (or perhaps multiple classes) with certain behavior. Gems such as _act_as_xxx_ come to mind fx.
|
29
|
-
|
30
|
-
I will soon try to generalize this pattern into a separate project and then have trole, troles and trole_groups all use this to leverage their functionality. Also, I will make use of an idea that I just had while taking a cold shower (try it sometime if you have a mind block!).
|
31
|
-
The idea is to have an internal default API, and an exposed API that by default is a reflection of the internal API. However the user is free to block parts of the API from being loaded or define his own external API that utilizes the inner API.
|
32
|
-
|
33
|
-
Since this is a general purpose decorator pattern, there should also be a kind of Index where you can see which decorators have been applied to an object and what API each such decorator exposes! Cool stuff!!!!
|
34
|
-
|
35
|
-
Some example usage:
|
36
|
-
<pre>
|
37
|
-
return if !User.has_decorator?(:troles_group)
|
38
|
-
# do some trole group stuff!!!
|
39
|
-
|
40
|
-
# later ...
|
41
|
-
|
42
|
-
# list all decorators currently applied to the User class
|
43
|
-
puts User.decorators
|
44
|
-
|
45
|
-
# print the methods of the public Write API for the :troles_group decorator :)
|
46
|
-
puts User.decorator(:troles_group).public_api(:write).methods.sort
|
47
|
-
|
48
|
-
# print the methods of the internal Write API for the :troles_group decorator :)
|
49
|
-
puts User.decorator(:troles_group).internal_api(:write).methods.sort
|
50
|
-
</pre>
|
51
|
-
|
52
|
-
I will use the new Decorator API very soon... sth like this:
|
53
|
-
|
54
|
-
<pre>
|
55
|
-
User.decorator(:trole_groups).configure(:strategy) :ref_one do |strategy|
|
56
|
-
strategy.orm = :mongoid
|
57
|
-
strategy.auto_load = true
|
58
|
-
end.configure!
|
59
|
-
</pre>
|
60
|
-
|
61
|
-
Awesome!
|
62
|
-
|
63
|
-
h3. Yard documentation
|
64
|
-
|
65
|
-
I'm using "Yard":http://rubydoc.info/docs/yard/file/docs/GettingStarted.md for documentation.
|
66
|
-
|
67
|
-
<pre>$ yard server
|
68
|
-
|
69
|
-
From browser, go to: http://0.0.0.0:8808/ # then you can enjoy! the nice documentation :)
|
70
|
-
</pre>
|
71
|
-
|
72
|
-
There is now support for Caching and invalidation of the _role_list_ when the roles change.
|
73
|
-
The specs now validate that caching works as it should.
|
74
|
-
|
75
|
-
Please help out to finalize this project! :)
|
76
|
-
|
77
|
-
h2. Bug hunting by running specs
|
78
|
-
|
79
|
-
Run specs for at most one strategy at the time for now...
|
80
|
-
|
81
|
-
@$ rspec spec/troles/strategies/bit_many_spec.rb@
|
82
|
-
|
83
|
-
Please see the document _spec/Guide to running specs.textile_ where I advise on how best to do "bug hunting" to help get this project off the ground!
|
84
|
-
|
85
16
|
h2. Role strategies
|
86
17
|
|
87
18
|
The following lists the role strategies to be supported
|
@@ -131,47 +62,47 @@ These strategies can be implemented for any data store using any schema format.
|
|
131
62
|
|
132
63
|
h3. Using roles strategies with Users and User accounts
|
133
64
|
|
134
|
-
Roles are assigned to role subject classes such as _User_ or _UserAccount_ (YES, Devise can have multiple user accounts!). The class that has a role strategy assigned is referred to as the _role subject class_.
|
135
|
-
Different role subject classes can have different role strategies!
|
65
|
+
Roles are assigned to role subject classes such as _User_ or _UserAccount_ (YES, Devise can have multiple user accounts!). The class that has a role strategy assigned is referred to as the _role subject class_. Different role subject classes can have different role strategies!
|
136
66
|
|
137
67
|
When using Devise this could translate fx into a UserAccount with a "many roles" strategy and an AdminAccount with a "single role" strategy (or vice versa).
|
138
68
|
|
139
69
|
Example:
|
140
70
|
|
141
|
-
<pre>
|
142
|
-
|
143
|
-
require 'troles/macros'
|
144
|
-
|
145
|
-
class UserAccount
|
146
|
-
troles_strategy(:string_many).configure!
|
147
|
-
end
|
71
|
+
<pre>require 'troles'
|
72
|
+
require 'troles/macros'
|
148
73
|
|
149
|
-
|
150
|
-
|
151
|
-
|
74
|
+
class UserAccount
|
75
|
+
troles_strategy(:string_many).configure!
|
76
|
+
end
|
77
|
+
|
78
|
+
class AdminAccount
|
79
|
+
troles_strategy(:bit_one, :static => true).configure!
|
80
|
+
end
|
152
81
|
</pre>
|
153
82
|
|
154
|
-
The special troles macros must be enabled my requiring the
|
83
|
+
The special troles macros must currently be enabled my requiring the _troles/macros_ file.
|
84
|
+
If the troles macros are not included like this, the troles DSL can be made available for an individual class by including a specific Strategy.
|
85
|
+
Using the macros like in the above example is much easier and is recommended.
|
155
86
|
|
156
87
|
h3. Macro options
|
157
88
|
|
158
89
|
The @:static => true@ options is used to indicate, that the role can not be changed after being initially set.
|
159
|
-
But we are getting ahead of ourselves... (more on this later).
|
160
|
-
|
90
|
+
But we are getting ahead of ourselves... (more on this later). Troles can easily be extended to support other macro options if needed.
|
91
|
+
Note: This static roles functionality is currently in-progress... (used to work but under change).
|
161
92
|
|
162
93
|
h2. Roles API
|
163
94
|
|
164
95
|
The Roles API can be divided into:
|
165
96
|
|
166
97
|
* Core
|
167
|
-
* Event
|
98
|
+
* Event
|
99
|
+
* Cache
|
168
100
|
* Read
|
169
101
|
* Write
|
170
|
-
* Store
|
171
102
|
* Validation
|
172
103
|
* Operations object
|
173
104
|
|
174
|
-
There is an
|
105
|
+
There is an equivalent Trole API for single role strategies.
|
175
106
|
|
176
107
|
h3. Event/Cache API
|
177
108
|
|
@@ -181,46 +112,33 @@ can have subscribers to events.
|
|
181
112
|
|
182
113
|
Also any write event to the datastore should be predicated on _#static_roles?_ not being true for the user (thus ensuring guest roles are never updated).
|
183
114
|
|
184
|
-
|
185
|
-
<pre>
|
186
|
-
User
|
187
|
-
after_save: update_roles # event handler
|
188
|
-
</pre>
|
189
|
-
|
190
|
-
<pre>
|
191
|
-
module Troles::Api::Event
|
192
|
-
def update_roles
|
193
|
-
def publish_change event
|
194
|
-
</pre>
|
115
|
+
@User.after_save: update_roles # event handler@
|
195
116
|
|
196
117
|
h3. Roles Read API
|
197
118
|
|
198
119
|
This API operates directly on a user, fx _user#has_role?_
|
199
120
|
|
200
|
-
<pre>
|
201
|
-
|
202
|
-
|
203
|
-
user.has_any_roles? :editor, :admin
|
121
|
+
<pre>user.has_role? :admin
|
122
|
+
user.is_role? :editor
|
123
|
+
user.has_any_roles? :editor, :admin
|
204
124
|
</pre>
|
205
125
|
|
206
126
|
h3. Roles Write API
|
207
127
|
|
208
128
|
This API operates directly on a user, fx _user#has_role?_
|
209
129
|
|
210
|
-
<pre>
|
211
|
-
|
212
|
-
user.remove_role :editor
|
130
|
+
<pre>user.add_role :admin
|
131
|
+
user.remove_role :editor
|
213
132
|
</pre>
|
214
133
|
|
215
134
|
h3. Roles Operations object
|
216
135
|
|
217
136
|
The Roles Operations object is available on user#roles
|
218
137
|
|
219
|
-
<pre>
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
user.roles.clear!
|
138
|
+
<pre>user.roles + :admin
|
139
|
+
user.roles - :editor
|
140
|
+
user.roles << [:editor, :admin]
|
141
|
+
user.roles.clear!
|
224
142
|
</pre>
|
225
143
|
|
226
144
|
h3. Creating a custom Data Store Adapter (DSA)
|
@@ -231,11 +149,9 @@ Note that :single role strategies always have the namespace 'Trole' whereas for
|
|
231
149
|
|
232
150
|
A custom Config class for _:single_ role strategies using _Mongoid_ could look sth. like this:
|
233
151
|
|
234
|
-
<pre>
|
235
|
-
module Trole::Mongoid
|
152
|
+
<pre>module Trole::Mongoid
|
236
153
|
class Config < Troles::Common::Config
|
237
|
-
|
238
|
-
def initialize subject_class, options = {}
|
154
|
+
def initialize subject, options = {}
|
239
155
|
super
|
240
156
|
end
|
241
157
|
|
@@ -265,8 +181,7 @@ See the _schema_helpers.rb_ file for more details!
|
|
265
181
|
|
266
182
|
Example: Config class for :many roles strategies with _Mongoid_
|
267
183
|
|
268
|
-
<pre>
|
269
|
-
module Troles::Mongoid
|
184
|
+
<pre>module Troles::Mongoid
|
270
185
|
class Config < Troles::Common::Config
|
271
186
|
|
272
187
|
def initialize subject_class, options = {}
|
@@ -305,8 +220,7 @@ Note: #set_role is only required for :single role strategies. In this case #set_
|
|
305
220
|
|
306
221
|
Example custom SSA (encrypted role string):
|
307
222
|
|
308
|
-
<pre>
|
309
|
-
module Trole::Storage
|
223
|
+
<pre>module Trole::Storage
|
310
224
|
module EncryptedStringOne < BaseOne
|
311
225
|
def initialize role_subject
|
312
226
|
super
|
@@ -344,8 +258,7 @@ h3. Custom Storage for an ORM (or data store)
|
|
344
258
|
|
345
259
|
In some cases it is useful to rewrite part of the base Storage functionality. One such method is #find_roles.
|
346
260
|
|
347
|
-
<pre>
|
348
|
-
module Troles::Storage
|
261
|
+
<pre>module Troles::Storage
|
349
262
|
class BaseMany < Troles::Common::Storage
|
350
263
|
def find_roles *roles
|
351
264
|
role_model.where(:name => roles.flatten).all
|
@@ -357,8 +270,7 @@ end
|
|
357
270
|
Active Record and Mongoid both implement the above API, so no need to customize this method in the Storage adapter.
|
358
271
|
For most other ORMs/data stores you will likely have to write your own logic to achieve this.
|
359
272
|
|
360
|
-
<pre>
|
361
|
-
module Troles::MongoidStorage
|
273
|
+
<pre>module Troles::MongoidStorage
|
362
274
|
class RefMany < Troles::Storage::BaseMany
|
363
275
|
|
364
276
|
def find_roles *roles
|
@@ -371,10 +283,9 @@ h3. Custom data marshaller
|
|
371
283
|
|
372
284
|
You can also use a custom "Marshaller":http://en.wikipedia.org/wiki/Marshalling_%28computer_science%29 to store the roles in a non-standard format. This is used for the _BitMany_ strategy, which has a special _Marshaller::BitMask_ class which handles conversion between a list of symbols to an _Integer_ bitmap representing it (relative to a valid roles list!). You can create your own _Marshaller_, fx to encrypt the roles info or whatever you like!
|
373
285
|
|
374
|
-
<pre>
|
375
|
-
module Troles::Marshaller
|
286
|
+
<pre>module Troles::Marshaller
|
376
287
|
class Encryption < Generic
|
377
|
-
def initialize
|
288
|
+
def initialize subject
|
378
289
|
super
|
379
290
|
end
|
380
291
|
|
@@ -395,8 +306,7 @@ h3. Using a custom Marshaller in a Storage implementation
|
|
395
306
|
|
396
307
|
The following example is taken from the BitOne Storage implementation that is part of troles:
|
397
308
|
|
398
|
-
<pre>
|
399
|
-
require 'troles/common/marshaller'
|
309
|
+
<pre>require 'troles/common/marshaller'
|
400
310
|
|
401
311
|
module Trole::Storage
|
402
312
|
class BitOne < BaseOne
|
@@ -432,10 +342,9 @@ Note that the same _BitMask_ marshaller is also reused in the _BitMany_ storage!
|
|
432
342
|
|
433
343
|
The _#bitmask_ method returns an instance of the _Bitmask_ marshaller, instantiated with the _role_subject_ (the instance that has the #role_list method, typically the user or user account). To use the _Encryption_ marshaller in an Encryption storage we could create a _#marshaller_ method:
|
434
344
|
|
435
|
-
<pre>
|
436
|
-
|
437
|
-
|
438
|
-
end
|
345
|
+
<pre>def marshaller
|
346
|
+
@marshaller ||= Troles::Marshaller::Encryption.new role_subject
|
347
|
+
end
|
439
348
|
</pre>
|
440
349
|
|
441
350
|
Then use @marshaller.write(*roles)@ in the _set_xxxx_ methods and @marshaller.read@ in _#display_roles_ method of the storage, as needed.
|
@@ -456,8 +365,7 @@ You rarely need to implement a custom Strategy module or custom API implementati
|
|
456
365
|
Here is an example of a custom Strategy implementation for _EncryptedStringMany_ that simply wraps the _BaseMany_ strategy implementation.
|
457
366
|
This example demonstrates how you can easily override functionality with custom implementations by including modules "on top".
|
458
367
|
|
459
|
-
<pre>
|
460
|
-
module Troles::Strategy
|
368
|
+
<pre>module Troles::Strategy
|
461
369
|
module EncryptedStringMany
|
462
370
|
|
463
371
|
# What to add to the role subject class when this role strategy is included
|
@@ -485,28 +393,25 @@ In some cases you need a custom Base strategy that contains common functionality
|
|
485
393
|
|
486
394
|
Example: _BaseMany_, used as the base for all Many roles strategies
|
487
395
|
|
488
|
-
<pre>
|
489
|
-
module
|
490
|
-
module
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
# base.extend ClassMethods
|
499
|
-
end
|
396
|
+
<pre>module Troles::Mongoid
|
397
|
+
module Strategy
|
398
|
+
module BaseMany
|
399
|
+
# @param [Class] the role subject class for which to include the Role strategy (fx User Account)
|
400
|
+
#
|
401
|
+
def self.included(base)
|
402
|
+
base.send :include, Troles::Strategy::BaseMany
|
403
|
+
|
404
|
+
# base.send :include, InstanceMethods
|
405
|
+
# base.extend ClassMethods
|
500
406
|
end
|
501
407
|
end
|
502
408
|
end
|
409
|
+
end
|
503
410
|
</pre>
|
504
411
|
|
505
412
|
To use your adapter, simply pass an extra option to the _troles_strategy_ macro:
|
506
413
|
|
507
|
-
|
508
|
-
User.troles_strategy(:bit_one, :orm => :mongoid).configure!
|
509
|
-
</pre>
|
414
|
+
@User.troles_strategy(:bit_one, :orm => :mongoid).configure!@
|
510
415
|
|
511
416
|
This even allows you to use different ORM role strategies/storages for different user accounts simultaneously!!!
|
512
417
|
|
@@ -514,22 +419,17 @@ Using the :auto_load option will 'auto load' (i.e require) the orm adapter from
|
|
514
419
|
You can include a specific custom (or 3rd party) adapter manually. In the future it will be possible to configure troles with adapters
|
515
420
|
and specify how/where to load them from as part of this configuration!
|
516
421
|
|
517
|
-
|
518
|
-
User.troles_strategy(:bit_one, :orm => :mongoid, :auto_load => true).configure!
|
519
|
-
</pre>
|
422
|
+
@User.troles_strategy(:bit_one, :orm => :mongoid, :auto_load => true).configure!@
|
520
423
|
|
521
424
|
You can also specify some of the options relevant to model configuration on the call to #configure if you like ;)
|
522
425
|
|
523
|
-
|
524
|
-
User.troles_strategy(:bit_one, :orm => :active_record, :auto_load => true).configure! :role_model => 'Troll'
|
525
|
-
</pre>
|
426
|
+
@User.troles_strategy(:bit_one, :orm => :active_record, :auto_load => true).configure! :role_model => 'Troll'@
|
526
427
|
|
527
428
|
The _troles_strategy_ macro will yield the Config object if you pass it a block.
|
528
429
|
This allows you to configure your stategy with troles inside the block and then call _configure!_ on end of the block.
|
529
430
|
Using all this in combination, you could configure it all doing sth. like this:
|
530
431
|
|
531
|
-
<pre>
|
532
|
-
require 'my/own/active_record/adapter'
|
432
|
+
<pre>require 'my/own/active_record/adapter'
|
533
433
|
|
534
434
|
User.troles_strategy :bit_one, :orm => :active_record do |c|
|
535
435
|
c.auto_load = false
|
@@ -591,14 +491,13 @@ _troles_ will be part of a larger project under development that will go under t
|
|
591
491
|
|
592
492
|
h3. Guest users
|
593
493
|
|
594
|
-
From the Devise wiki:
|
494
|
+
From the "Devise wiki":https://github.com/plataformatec/devise/wiki/How-To:-Create-a-guest-user
|
595
495
|
|
596
496
|
"In some applications, it's useful to have a guest User object to pass around even before the (human) user has registered or logged in. Normally, you want this guest user to persist as long as the browser session persists.
|
597
497
|
|
598
498
|
Our approach is to create a guest user object in the database and store its id in session[:guest_user_id]. When (and if) the user registers or logs in, we delete the guest user and clear the session variable. A helper function, current_or_guest_user, returns guest_user if the user is not logged in and current_user if the user is logged in."
|
599
499
|
|
600
|
-
<pre>
|
601
|
-
module ApplicationHelper
|
500
|
+
<pre>module ApplicationHelper
|
602
501
|
...
|
603
502
|
# if user is logged in, return current_user, else return guest_user
|
604
503
|
def current_or_guest_user
|
@@ -631,9 +530,7 @@ end
|
|
631
530
|
|
632
531
|
In the new system, I propose the following:
|
633
532
|
|
634
|
-
<pre
|
635
|
-
|
636
|
-
# this will make the current user the guest user account for the given scope!
|
533
|
+
<pre># this will make the current user the guest user account for the given scope!
|
637
534
|
def sign_in_guest scope, options = {}
|
638
535
|
warden.set_user(guest_user.account, options.merge!(:scope => scope))
|
639
536
|
end
|
@@ -665,8 +562,7 @@ def guest_user
|
|
665
562
|
end
|
666
563
|
</pre>
|
667
564
|
|
668
|
-
<pre>
|
669
|
-
class GuestUserAccount
|
565
|
+
<pre>class GuestUserAccount
|
670
566
|
troles_strategy(:static_one, :role => :guest) do |c|
|
671
567
|
# c.valid_roles = [:guest] not needed!
|
672
568
|
end.configure!
|
@@ -685,8 +581,7 @@ end
|
|
685
581
|
|
686
582
|
Here the special _:static_many_ strategy is used, which means that whatever the _role_list_ is first set to can never change for that user.
|
687
583
|
|
688
|
-
<pre>
|
689
|
-
module BaseAccount
|
584
|
+
<pre>module BaseAccount
|
690
585
|
# transfer guest settings to logged_in user/account
|
691
586
|
def transfer_guest(guest_user)
|
692
587
|
end
|
@@ -711,8 +606,7 @@ end
|
|
711
606
|
|
712
607
|
And here the User setup:
|
713
608
|
|
714
|
-
<pre>
|
715
|
-
module BaseUser
|
609
|
+
<pre>module BaseUser
|
716
610
|
end
|
717
611
|
|
718
612
|
class User
|
@@ -726,8 +620,7 @@ class User
|
|
726
620
|
end
|
727
621
|
</pre>
|
728
622
|
|
729
|
-
<pre>
|
730
|
-
class GuestUser
|
623
|
+
<pre>class GuestUser
|
731
624
|
include BaseUser
|
732
625
|
|
733
626
|
def account
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.5.
|
1
|
+
0.5.2
|
data/lib/trole.rb
CHANGED
@@ -28,7 +28,11 @@ module TroleGroups
|
|
28
28
|
# sets the value of the role field (@trole or @troles) and persists the value (in the data store)
|
29
29
|
# @param [Object] the value to set on the role field of the role subject
|
30
30
|
def set_ds_field value
|
31
|
-
return if ds_field_value == value
|
31
|
+
return if ds_field_value == value
|
32
|
+
if Troles::Common::Config.log_on?
|
33
|
+
puts "TroleGroups::Storage::BaseMany.set_ds_field:"
|
34
|
+
puts "#{rolegroup_subject}.#{ds_field_name} = #{value}"
|
35
|
+
end
|
32
36
|
rolegroup_subject.send(:"#{ds_field_name}=", value)
|
33
37
|
persist_role_changes!
|
34
38
|
end
|
@@ -42,15 +46,22 @@ module TroleGroups
|
|
42
46
|
# the current value of the role field
|
43
47
|
# @return [Object] the value
|
44
48
|
def ds_field_value
|
49
|
+
# puts "#{rolegroup_subject}.#{ds_field_name}" if Troles::Common::Config.log_on?
|
45
50
|
rolegroup_subject.send(ds_field_name)
|
46
51
|
end
|
47
52
|
|
48
53
|
# Attempts to persist the role field changes
|
49
54
|
# @return [true, false, error] true if saved, false if no save! method, Error on some error
|
50
|
-
def persist_role_changes!
|
51
|
-
|
52
|
-
rolegroup_subject.save
|
53
|
-
|
55
|
+
def persist_role_changes!
|
56
|
+
puts "TroleGroups::Storage::BaseMany.persist_role_changes!" if Troles::Common::Config.log_on?
|
57
|
+
if !rolegroup_subject.respond_to? :save
|
58
|
+
puts "could not save since no #save method on subject: #{rolegroup_subject}" if Troles::Common::Config.log_on?
|
59
|
+
return false
|
60
|
+
else
|
61
|
+
puts "#{rolegroup_subject}.save" if Troles::Common::Config.log_on?
|
62
|
+
rolegroup_subject.save
|
63
|
+
rolegroup_subject.publish_change :role_groups
|
64
|
+
end
|
54
65
|
end
|
55
66
|
|
56
67
|
protected
|
@@ -7,8 +7,10 @@ module Troles::ActiveRecord
|
|
7
7
|
|
8
8
|
def configure_relation
|
9
9
|
case strategy
|
10
|
+
when :join_ref_many
|
11
|
+
configure_join_model
|
10
12
|
when :ref_many
|
11
|
-
return configure_join_model if
|
13
|
+
return configure_join_model if join_model
|
12
14
|
has_and_belongs_many subject_class, object_model, :key => :accounts
|
13
15
|
when :embed_many
|
14
16
|
raise "Embed many configuration not yet implemented for ActiveRecord"
|
@@ -25,6 +27,11 @@ module Troles::ActiveRecord
|
|
25
27
|
role_model
|
26
28
|
end
|
27
29
|
|
30
|
+
def join_model
|
31
|
+
role_join_model
|
32
|
+
end
|
33
|
+
|
34
|
+
|
28
35
|
def role_join_model
|
29
36
|
@join_model_found ||= begin
|
30
37
|
models = [@join_model, join_model_best_guess].select do |class_name|
|
@@ -50,10 +57,17 @@ module Troles::ActiveRecord
|
|
50
57
|
make_key role_join_model
|
51
58
|
end
|
52
59
|
|
53
|
-
def configure_join_model
|
60
|
+
def configure_join_model
|
61
|
+
if Troles::Common::Config.log_on?
|
62
|
+
puts "configuring join model..."
|
63
|
+
puts "Subject class: #{subject_class}"
|
64
|
+
puts "Role class: #{object_model}"
|
65
|
+
puts "Join class: #{join_model}"
|
66
|
+
end
|
67
|
+
|
54
68
|
# UserAccount
|
55
69
|
# has_many :troles, :class_name => 'Role', :through => :users_roles
|
56
|
-
has_many_for subject_class,
|
70
|
+
has_many_for subject_class, object_model, :opts => {:through => join_key.to_sym}
|
57
71
|
# has_many :user_roles, :class_name => 'UserRole'
|
58
72
|
has_many_for subject_class, role_join_model, :key => join_key
|
59
73
|
|
@@ -65,10 +79,10 @@ module Troles::ActiveRecord
|
|
65
79
|
|
66
80
|
# Role
|
67
81
|
# has_many :accounts, :class_name => 'User', :through => :user_roles
|
68
|
-
has_many_for
|
82
|
+
has_many_for object_model, subject_class, :key => :accounts, :opts => {:through => join_key.to_sym}
|
69
83
|
|
70
84
|
# has_many :user_roles, :class_name => 'UserRole'
|
71
|
-
has_many_for
|
85
|
+
has_many_for object_model, role_join_model, :key => join_key
|
72
86
|
end
|
73
87
|
end
|
74
88
|
end
|
data/lib/troles/api/config.rb
CHANGED
data/lib/troles/api/core.rb
CHANGED
@@ -5,18 +5,18 @@
|
|
5
5
|
#
|
6
6
|
module Troles::Common::Api
|
7
7
|
module Core
|
8
|
-
|
8
|
+
|
9
9
|
# Access to the Troles operations API
|
10
10
|
# @return [Troles::Operations] the operations API object
|
11
11
|
def roles
|
12
12
|
@roles ||= Troles::Operations.new(self)
|
13
|
-
end
|
13
|
+
end
|
14
14
|
|
15
15
|
# Sets the roles of the subject
|
16
16
|
# (see #set_roles)
|
17
17
|
def roles= *new_roles
|
18
18
|
roles.set_roles new_roles
|
19
|
-
end
|
19
|
+
end
|
20
20
|
|
21
21
|
# If this role subject instance should have static (immutable) roles
|
22
22
|
# @return [true, false] defaults to false so a role subject is allowed to change roles
|
@@ -25,28 +25,27 @@ module Troles::Common::Api
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def troles_config
|
28
|
-
self.class.troles_config
|
28
|
+
self.class.troles_config
|
29
29
|
end
|
30
|
-
|
31
|
-
module ClassMethods
|
32
|
-
|
30
|
+
|
31
|
+
module ClassMethods
|
32
|
+
|
33
33
|
def valid_roles
|
34
34
|
troles_config.valid_roles
|
35
35
|
end
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
# end
|
37
|
+
def valid_roles= *roles
|
38
|
+
troles_config.valid_roles = roles.flatten.map{|r| r.to_s.alpha_numeric}.map(&:to_sym).uniq
|
39
|
+
end
|
41
40
|
|
42
41
|
# If all role subjects using this strategy should have static (immutable) roles
|
43
42
|
#
|
44
|
-
# @note Should also proxy Config object?
|
43
|
+
# @note Should also proxy Config object?
|
45
44
|
#
|
46
45
|
# @return [true, false] if role subjects have static roles or not (default: false)
|
47
46
|
def static_roles?
|
48
47
|
troles_config.static_roles?
|
49
|
-
end
|
48
|
+
end
|
50
49
|
end
|
51
50
|
end
|
52
|
-
end
|
51
|
+
end
|
@@ -39,6 +39,12 @@ module Troles::Common::Api
|
|
39
39
|
# (see #has_roles?)
|
40
40
|
def has_any_role? *roles
|
41
41
|
!(role_list & roles.to_symbols).empty?
|
42
|
+
end
|
43
|
+
|
44
|
+
# Checks if the role subject has any of the listed roles
|
45
|
+
# (see #has_roles?)
|
46
|
+
def has_all_roles? *roles
|
47
|
+
(roles.to_symbols - role_list).empty?
|
42
48
|
end
|
43
49
|
end
|
44
50
|
end
|
data/lib/troles/common/api.rb
CHANGED
@@ -15,14 +15,15 @@ module Troles::Common
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def included(base)
|
18
|
+
puts "Included #{base}"
|
18
19
|
apis.each do |api|
|
19
20
|
begin
|
20
21
|
base.include_and_extend :"#{api.to_s.camelize}"
|
21
22
|
rescue
|
22
23
|
end
|
23
|
-
end
|
24
|
+
end
|
24
25
|
end
|
25
26
|
end
|
26
27
|
extend ClassMethods
|
27
28
|
end
|
28
|
-
end
|
29
|
+
end
|