popel-active_acl_plus 0.4.4

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.
@@ -0,0 +1,317 @@
1
+ =Active Access Control Lists Plus (ActiveAclPlus)
2
+ The ActiveAclPlus plugin implements a flexible, fast and easy to use generic access control system.
3
+
4
+ ==License
5
+ ActiveAclPlus is released under the LGPL[http://www.opensource.org/licenses/lgpl-license.php]
6
+ (Gnu Lesser General Public License) - see the included LICENSE file, too.
7
+
8
+ ==Features
9
+ * ease of use - uses polymorphic collections for associations.
10
+ * advanced design - uses SQL nested sets for inheritance, thus only needs a single DB query to decide on a permission request.
11
+ * scalable - there are no real benchmarks yet. But the system design is based on http://phpgacl.sourceforge.net, adding object orientation, polymorphism and two levels of caching. PhpGacl claims "A real-world working version with many added layers of complexity supports over 60,000 Accounts, 200 Groups and 300 ACO's." Tests on my dev notebook show 10 - 30 times performance improvements compared to active_rbac.
12
+ * caching - uses instance caching and optionally stores permission results in memcached using timeouts.
13
+ * flexible - grants simple (2D, like <code>current_user.has_permission?(User::LOGIN)</code>) and object level (3D, like <code>admin.has_permission?(Forum::ADMIN, :on => team_forum)</code>) permissions. Can assign and request permissions to and from every ActiveRecord model. No "hardcoded" permissions - all permissions can be assigned at runtime.
14
+ * grouping - permissions can be inherited at target and requester side through groups. Every model implementing an SQL nested set tree may be used as a group.
15
+ * ControllerAction model loader: It maps controller actions to the DB so they can be used in permission assignment. The access object is available via calling <code>current_action</code> on the controller.
16
+ * exchangeable DB interface: ActiveRecord and direct MySQL adapter available
17
+ * supports namespaced models and single table inheritance (STI)
18
+
19
+ ==Limitations
20
+ * At present only one grouping type per model is supported. This could be changed on request but I don't see a use case for it yet.
21
+ * The DBMS has to support subselects. So PostgreSQL, Sqllite and MySQL 5 work, but MySQL 4 does not.
22
+
23
+
24
+ ==Prerequisites/Installation
25
+ ActiveAclPlus uses the has_many_polymorphs[http://www.agilewebdevelopment.com/plugins/restful_authentication] plugin. Make shure you've got a recent version, old versions have bugs affecting active_acl_plus.
26
+ !!Be sure you have the paches for 2.1, see: http://rubyforge.org/forum/forum.php?thread_id=26041&forum_id=16450
27
+
28
+ ./script/plugin install git://github.com/popel/active_acl_plus.git
29
+
30
+ or
31
+
32
+ sudo gem install activeaclplus
33
+
34
+ or from a github repository.
35
+
36
+ If you want to use grouped access objects you should install some kind of nested_set plugin
37
+ (awesome_nested_set,better_nested_set,...).
38
+ ==Short summary
39
+ The ActiveAclPlus system consists of access objects, which can be organized by access groups,
40
+ that request privileges on each other. Allowing or denying access to a privilege is controlled by
41
+ ACL (access control list entry) objects. Access objects and access groups can be instances of arbitrary
42
+ ActiveRecord model classes enhanced by acts_as_access_object and acts_as_access_group. They are associated
43
+ to ACL entries via polymorphic associations.
44
+
45
+ ===Access objects
46
+ These are basically requesters and targets in the permission system, as for example a User or a Forum model object.
47
+ In this case a user could act as a requester ("do I have privilege Y?") or target ("does access object X have
48
+ privilege Y on me?"). A Forum would most certainly be only used as a target, but all access objects can theoretically
49
+ be used as both requesters and targets. Access objects use the acts_as_access_object macro inside their definition.
50
+ This registers the model with the ACL system and enhances it with methods like has_privilege?.
51
+
52
+ See: ActiveAcl::Acts::AccessObject::ClassMethods, ActiveAcl::Acts::AccessObject::InstanceMethods,
53
+ ActiveAcl::Acts::AccessObject::SingletonMethods, ActiveAcl::Acts::Grant
54
+
55
+
56
+ Every access object class can specify an association that is used as the "grouping type" to it. So User may declare
57
+ has_and_belongs_to_many :user_groups and use acts_as_access_object :grouped_by => :user_groups. You can use
58
+ a has_and_belongs_to_many or a belongs_to association for this. Common mapping attributes
59
+ (:join_table, :foreign_key etc.) are supported.
60
+
61
+ ===Access groups
62
+ The access group model needs to implement a tree with nested set semantics having a "left" and "right"
63
+ column, e.g. by using the built-in acts_as_nested_set or the much more recommended acts_as_betted_nested_set
64
+ plugin. Groups are declared with acts_as_access_group.
65
+
66
+ Groups may be used to specify inheritance hierarchies for permissions. So you could have a 'registered users'
67
+ group as a subgroup of the 'users' group and assign the privilege to log in to this group via an ACL entry.
68
+ Every user belonging to this group will now be granted the privilege to log in. Then you could add a subgroup
69
+ to registerd users, 'banned users', and deny the log in privilege for this group. Every user added to this
70
+ group would now be unable to log in, regardless of beeing in 'registered users' or not, as 'banned users' would
71
+ override the permission settings of 'registered users'.
72
+
73
+ ===Privileges
74
+ A privilege object is an object for the thing we wish to define a permission for. So User::LOGIN could be a
75
+ privilege object for checking a users permission to log in, while Forum::ADMIN might define administration rights on a forum.
76
+
77
+ A privilege object itself is little more than it’s name and id and is usually bound to a constant inside the
78
+ application, as it is not expected to change at runtime. Privileges are usually created by the developer in
79
+ the source code and not in the admin frontend, as creating new privilege objects that have no meaning (by code
80
+ that checks for them) would be pointless.
81
+
82
+ ===Access Control List (ACL) entries
83
+ ACL entries are the glue between all these objects, defining which requesters and requester groups have access
84
+ to which privileges, optionally defining target objects and target groups as well. ACL entries are organized by
85
+ ACL sections, for better overview in the admin screens.
86
+
87
+ ==Usage
88
+ ===In short
89
+ "No access defined" for a privilege evaluates to "deny". This may be overriden by an explicit "allow" or "deny".
90
+ Privileges are inherited in requestor and target groups, this means you can override them in subgroups again.
91
+ Privileges directly assigned to an object always supercede those assigned to groups.
92
+
93
+ ===Simple (2D) permissions
94
+ We want all registered users to be able to log in. We create the User model, the UserGroup model and the
95
+ User::LOGIN privilege object as described above. Then we create a new ACL entry, set 'allow' to true, add
96
+ the "registered users" group as requester group, User::LOGIN as privilege and we are done. Every user assigned
97
+ to "registered users" or a subgroup of it will now be granted access by calling <code>my_user.has_privilege?(User::LOGIN)</code>.
98
+
99
+ ====Simple permissions example
100
+
101
+ class UserGroup < ActiveRecord::Base
102
+ acts_as_nested_set
103
+ acts_as_access_group
104
+ has_and_belongs_to_many :users
105
+ end
106
+
107
+ class User < ActiveRecord::Base
108
+ has_and_belongs_to_many :user_groups
109
+ acts_as_access_object :grouped_by => :user_groups
110
+ privilege_const_set('LOGIN')
111
+ end
112
+
113
+ # assume 'registered_users' exists and users 'john' and 'dr_evil' are members of it but 'anonymous' is not.
114
+ registered_users = UserGroup.find_by_name('registered_users')
115
+
116
+ the hard way:
117
+ acl = ActiveAcl::Acl.create :section => ActiveAcl::AclSection.create(:description => 'users')
118
+
119
+ acl.allow = true # true is default
120
+ acl.privileges << User::LOGIN
121
+ acl.iname="login"
122
+ acl.save
123
+
124
+ acl.requester_groups << registered_users
125
+
126
+ or much easier:
127
+
128
+ registered_users.grant_privilege!(User::LOGIN,:section_name => 'users',:acl_name => 'login')
129
+
130
+ john.has_privilege?(User::LOGIN) #=> true
131
+ dr_evil.has_privilege?(User::LOGIN) #=> true
132
+
133
+ anonymous.has_privilege?(User::LOGIN) #=> false
134
+
135
+ ===Overriding permissions
136
+ We want to ban specific users from our site. We create another ACL entry, assign the User::LOGIN privilege
137
+ object, set 'allow' to false and then assign these users as requesters to the ACL entry. The direct
138
+ permission assignment on the objects overrides the 'allow login' ACL entry from above.
139
+
140
+ ====Overriding permissions example
141
+
142
+ ban_users = ActiveAcl::Acl.create :section => ActiveAcl::AclSection.find_by_description('users')
143
+
144
+ ban_users.allow = false
145
+ ban_users.privileges << User::LOGIN
146
+ ban_users.requesters << dr_evil
147
+
148
+ ban_users.save
149
+
150
+ john.has_privilege?(User::LOGIN) #=> true
151
+ dr_evil.has_privilege?(User::LOGIN) #=> false
152
+
153
+ ===Object level (3D) permissions
154
+ We want to assign forum permissions. We have several privileges (Forum::ADMIN, Forum::READ, Forum::POST etc.),
155
+ the afore mentioned User and UserGroup models as well as a Forum and a Category model for grouping the forums.
156
+
157
+ If we want to check if a certain user may read in a certain forum, it is not sufficient to check
158
+ <code>test_user.has_privilege?(Forum::READ)</code> as the target object - in this case a forum - is needed
159
+ to make a decision. The code to do the check is like <code>test_user.has_privilege?(Forum::READ, :on => teamforum)</code>.
160
+
161
+ To make this work you create a new ACL entry, add Forum::POST and Forum::READ as privileges, set 'allow' to
162
+ true, add the registered users group as a requester group and the public forums category as a target group
163
+ to the acl. Now every user belonging to the registered users group or a subgroup of it gains post and read
164
+ privileges on all forums of the public forums category or a subcategory of it.
165
+
166
+ ====Object level permissions example
167
+
168
+ # Assuming setup as in the above examples
169
+
170
+ class Category < ActiveRecord::Base
171
+ acts_as_nested_set
172
+ acts_as_access_group
173
+ has_many :forums
174
+ end
175
+
176
+ class Forum < ActiveRecord::Base
177
+ belongs_to :category
178
+ acts_as_access_object :grouped_by => :category
179
+ privilege_const_set 'READ' => 'read postings in forum',
180
+ 'POST' => 'reply to threads in a forum'
181
+ end
182
+
183
+ # assume there is a forum 'speakers corner' assigned to the category 'public'.
184
+
185
+ acl = ActiveAcl::Acl.create :section => ActiveAcl::AclSection.create(:description => 'forum')
186
+
187
+ acl.allow = true
188
+ acl.requester_groups << registered_users
189
+ acl.target_groups << Category.find_by_name('public')
190
+
191
+ acl.privileges << Forum::READ
192
+ acl.privileges << Forum::POST
193
+
194
+ acl.save
195
+
196
+ speakers = Forum.find_by_name('speakers corner')
197
+
198
+ john.has_privilege?(Forum::READ, :on => speakers) #=> true
199
+ john.has_privilege?(Forum::POST, :on => speakers) #=> true
200
+ anonymous.has_privilege?(Forum::READ, :on => speakers) #=> false
201
+
202
+ ==CAUTION
203
+ Do not create ACL entries that are on different branches of the inheritance hierarchy and have
204
+ allow/deny set differently on the same privilege objects. This way it's impossible to tell which
205
+ permission should take precedence. At present this is by creation date, later entries superceding older
206
+ ones, but this is most certainly not what you want.
207
+
208
+ ==Controller Actions
209
+ Defining permissions on controller actions (like "may user x execute AdminController.list ?") is quite a
210
+ common case but we are facing a problem here: Controller actions have no corresponding DB models so
211
+ permissions on them can't be easily defined.
212
+
213
+ ActiveAclPlus solves this by adding a ControllerAction and ControllerGroup model. For every public
214
+ controller method (=action) there is one ControllerAction object in the DB.
215
+
216
+ On application startup, the plugin loader checks all controller files in app/controllers and loads
217
+ or creates a ControllerAction object for every action it finds. These objects get cached in a hash
218
+ in the ActiveAclPlus module. Every controller now has a method <code>current_action</code> that looks
219
+ up and returns the access object for the current action, so it can be used for access checks like
220
+ <code>current_user.has_privilege?(ActiveAcl::ControllerAction::EXECUTE, :on => current_action)</code>.
221
+
222
+ This works nicely for before_filters with authorization checks.
223
+
224
+ A word on the load mechanism: If the action has no corresponding DB entry (it's looked up on method creation
225
+ by controller and action name) the loader searches for a controller group with the same name as the
226
+ controller. If it is found, the action is created and assigned to this group. Else the controller group
227
+ is created as a subgroup to the "unassigned controller actions" group (this name can be changed in the
228
+ options) and the unassigned action is added to the controller group.
229
+
230
+ So you are free on how to organize your controllers. Maybe create an admin group and a public group and
231
+ move controllers as a subgroup inside them?
232
+
233
+ ==Caching
234
+ The plugin provides two levels of caching. The instance cache is a hash inside the access object. The object
235
+ first tries to serve a permission request from the instance cache. If it is not found and a simple permission
236
+ is requested, the query fetches all simple permissions (2D) of the object and puts them in the instance cache. The
237
+ reason for this is that there is no noticable speed penalty in fetching all 2D permissions at once compared to
238
+ fetching only one, so this will save time and DB IO later on. Complex 3D queries are fetched independently
239
+ and also saved to the instance cache. The instance cache lives inside the access object, so it has it's
240
+ lifetime, too - which in rails usually is no more than a single request.
241
+
242
+ The second level cache tries to overcome this limitation by putting the instance cache of an access object
243
+ in an external cache. It tries to get the instance cache from there if it is not set, and sets it if it was
244
+ changed. The only real implementation for now is with the memcache daemon. The second level cache uses a timeout
245
+ (which can be defined in the options) to expire the cached permissions.
246
+
247
+ Instance and second level cache can be expired explicitly by calling <code>active_acl_clear_cache!</code>
248
+ on the access object. Calling <code>reload</code> on the object also purges the caches.
249
+
250
+ See ActiveAcl::Cache::MemcacheAdapter on how to set it up.
251
+
252
+
253
+ ==Preloader
254
+ The plugin includes a <code>load_files_from filenames</code> function. It can be used to preload source files
255
+ (and therefore the classes in it) from an application path and should be used from environment.rb.
256
+
257
+ load_files_from("#{RAILS_ROOT}/app/controllers/**/[^.]*.rb")
258
+ load_files_from("#{RAILS_ROOT}/app/models/**/[^.]*.rb")
259
+
260
+ will load all models and controllers inside these folders and their subfolders. This way you can be shure they
261
+ are registered with the ACL system at rails boot time - else they will be registered when they are called for
262
+ the first time. This means that new controllers will not show up in the admin screens until they were accessed
263
+ if not using the preloader.
264
+
265
+ ==Options
266
+ <code>ActiveAcl::OPTIONS</code> is an array that can be used to override various options for the system by setting
267
+ the values in environment.rb. <code>ActiveAcl::DEFAULT_OPTIONS</code> is as follows:
268
+
269
+ DEFAULT_OPTIONS = {
270
+ :acl_sections_table => 'acl_sections',
271
+ :acls_privileges_table => 'acls_privileges',
272
+ :acls_table => 'acls',
273
+ :privileges_table => 'privileges',
274
+ :requester_links_table => 'requester_links',
275
+ :target_links_table => 'target_links',
276
+ :requester_group_links_table => 'requester_group_links',
277
+ :target_group_links_table => 'target_group_links',
278
+ :controller_actions_table => 'controller_actions',
279
+ :controller_groups_table => 'controller_groups',
280
+
281
+ :controllers_group_name => 'unassigned_controller_actions', # the name of the base group
282
+ # that newly created controller groups get assigned to
283
+ :controller_group_name_suffix => '_controller', # name suffix for generated controller groups
284
+
285
+ :cache_permission_timeout => 10, # timeout in seconds for the second level cache
286
+
287
+ :db => ActiveAcl::DB::ActiveRecordAdapter, # the DB Adapter to use
288
+ :cache => ActiveAcl::Cache::NoCacheAdapter, # the Cache Adapter to use
289
+ }
290
+
291
+ ==Tests
292
+ Not anymore, sorry. I'm using RSpec for testing. A repository
293
+ is/will be setup at http://github.com/popel/active_acl_plus_rspec/tree/master . Check it out and move it to "spec". Run
294
+ rake spec
295
+
296
+ ==Credits
297
+ * Gregor Melhorn implemented this and maintained it up to Version 0.2.1. Thanks for releasing this!
298
+ * Evan for writing that great polymorph plugin and beeing so kind to add namespace and tablename support on Gregor's request.
299
+ * ReinH and markmeves for great support and suggestions at the rubyonrails channel on freenode.org.
300
+ * http://phpgacl.sourceforge.net as a great source of inspiration
301
+ * Obrie for writing plugin_migrations and loaded_plugins and also very nice support when Gregor got stuck with using them.
302
+
303
+ ==ToDo/Ideas
304
+
305
+ in no particular order, just a reminder...
306
+
307
+ * add materialized_tree support
308
+ * use Moneta as key/value store
309
+ * direct PostgreSQL interface
310
+ * example on how to integrate with authentication
311
+ * example on controller actions
312
+ * error checking for conflicting ACL entries
313
+ * get all permissions for a requester within a section
314
+ * get all permissions of a requester (with one query)
315
+ * get all permissions of a requester on a target (with one query)
316
+ * get all requester with a given privilege on a target (one query)
317
+ * get all targets on which a requester has a certain privilege (one query)
@@ -0,0 +1,4 @@
1
+ ---
2
+ :minor: 4
3
+ :patch: 4
4
+ :major: 0
@@ -0,0 +1,32 @@
1
+ module ActiveAcl
2
+
3
+
4
+ end
5
+
6
+ # plugin dependency
7
+ require 'has_many_polymorphs'
8
+
9
+ require 'active_acl/db/active_record_adapter'
10
+ require 'active_acl/cache/no_cache_adapter'
11
+ require 'active_acl/options'
12
+ require 'active_acl/base'
13
+
14
+ require 'active_acl/privilege_const_set'
15
+ require 'active_acl/grant'
16
+
17
+ require 'active_acl/handler/object_handler'
18
+ require 'active_acl/handler/nested_set'
19
+ require 'active_acl/load_controller_actions'
20
+ require 'active_acl/acts_as_access_object'
21
+ require 'active_acl/acts_as_access_group'
22
+ require 'active_acl/load_files_from'
23
+
24
+
25
+ # call class so its loaded and registered as access object
26
+ # wrap in rescue block so migrations don't fail
27
+ begin
28
+ ActiveAcl::ControllerAction
29
+ ActiveAcl::ControllerGroup
30
+ rescue StandardError => e
31
+ puts "Error #{e.message} #{e.backtrace.join("\n")}(need migrations?)"
32
+ end
@@ -0,0 +1,57 @@
1
+ require 'active_record'
2
+
3
+ module ActiveAcl #:nodoc:
4
+ module Acts #:nodoc:
5
+ module AccessGroup #:nodoc:
6
+
7
+ def self.included(base)
8
+ base.extend(ClassMethods)
9
+ end
10
+
11
+ module ClassMethods
12
+ # Extend self with access group capabilites.
13
+ # Options can be:
14
+ # type:: is mandatory and is one of the group handler classes
15
+ # left_column:: for ActiveAcl::Acts::AccessGroup::NestedSet grouped objects
16
+ # right_column:: for ActiveAcl::Acts::AccessGroup::NestedSet grouped objects
17
+
18
+ def acts_as_access_group(options = {})
19
+ type=options.delete(:type) || ActiveAcl::Acts::AccessGroup::NestedSet
20
+ ActiveAcl.register_group(self,type.new(options))
21
+
22
+ include ActiveAcl::Acts::Grant
23
+ include InstanceMethods
24
+ extend SingletonMethods
25
+
26
+ ActiveAcl::Acl.instance_eval do
27
+ has_many_polymorphs :requester_groups, {:from => ActiveAcl.from_classes,
28
+ :through => :"active_acl/requester_group_links",
29
+ :rename_individual_collections => true}
30
+
31
+ has_many_polymorphs :target_groups, {:from => ActiveAcl.from_classes,
32
+ :through => :"active_acl/target_group_links",
33
+ :rename_individual_collections => true}
34
+ end
35
+
36
+ end
37
+ end
38
+
39
+ module SingletonMethods
40
+ # class description in engine interface
41
+ def active_acl_description
42
+ name
43
+ end
44
+ end
45
+
46
+ module InstanceMethods
47
+ # override this to customize the description in the interface
48
+ def active_acl_description
49
+ to_s
50
+ end
51
+ end
52
+
53
+ end
54
+ end
55
+ end
56
+
57
+ ActiveRecord::Base.send(:include, ActiveAcl::Acts::AccessGroup)
@@ -0,0 +1,114 @@
1
+ #require 'direct_handler'
2
+
3
+ module ActiveAcl #:nodoc:
4
+ module Acts #:nodoc:
5
+ module AccessObject #:nodoc:
6
+
7
+ def self.included(base)
8
+ base.extend(ClassMethods)
9
+ end
10
+
11
+ module ClassMethods
12
+
13
+ # Extend self with access object capabilites. See README for details
14
+ # on usage. Accepts the following options as a hash:
15
+ # grouped_by:: name of the association acting as a group for access privilege
16
+ # group_class_name:: class name of group class
17
+ # join_table:: name of the join table
18
+ # foreign_key:: foreign key of self in the join table
19
+ # association_foreign_key:: foreign_key of the group class
20
+ # habtm:: set to <code>true</code> if the grup is joined with a habtm association.
21
+ # If not specified, the plugin tries to guess if the association is
22
+ # has_and_belongs_to_many or belongs_to by creating the singular form of the
23
+ # :grouped_by option and comparing it to itself: If it matches, it assumes a belongs_to association.
24
+ def acts_as_access_object(options = {})
25
+
26
+ handler=ObjectHandler.new(self,options)
27
+
28
+ ActiveAcl.register_object(self,handler)
29
+
30
+ has_many :requester_links, :as => :requester, :dependent => :delete_all, :class_name => 'ActiveAcl::RequesterLink'
31
+ has_many :requester_acls, :through => :requester_links, :source => :acl, :class_name => 'ActiveAcl::Acl'
32
+
33
+ has_many :target_links, :as => :target, :dependent => :delete_all, :class_name => 'ActiveAcl::TargetLink'
34
+ has_many :target_acls, :through => :target_links, :source => :acl, :class_name => 'ActiveAcl::Acl'
35
+
36
+ include InstanceMethods
37
+ extend SingletonMethods
38
+ include ActiveAcl::Acts::Grant
39
+
40
+ ActiveAcl::Acl.instance_eval do
41
+ has_many_polymorphs :requesters, {:from => ActiveAcl.from_classes,
42
+ :through => :"active_acl/requester_links",
43
+ :rename_individual_collections => true}
44
+
45
+ has_many_polymorphs :targets, {:from => ActiveAcl.from_classes,
46
+ :through => :"active_acl/target_links",
47
+ :rename_individual_collections => true}
48
+ end
49
+
50
+ self.module_eval do
51
+ # checks if method is defined to not break tests
52
+ unless instance_methods.include? "reload_before_active_acl"
53
+ alias :reload_before_active_acl :reload
54
+
55
+ # Redefines reload, making shure privilege caches are cleared on reload
56
+ def reload #:nodoc:
57
+ active_acl_clear_cache!
58
+ reload_before_active_acl
59
+ end
60
+ end
61
+ end
62
+
63
+ end
64
+ end
65
+
66
+ module SingletonMethods
67
+ # class description in engine interface
68
+ def active_acl_description
69
+ return name
70
+ end
71
+ end
72
+
73
+ module InstanceMethods
74
+
75
+ # checks if the user has a certain privilege, optionally on the given object.
76
+ # Option :on defines the target object.
77
+ def has_privilege?(privilege, options = {})
78
+ target = options[:on] #TODO: add error handling if not a hash
79
+ # no need to check anything if privilege is not a Privilege
80
+ raise "first Argument has to be a Privilege" unless privilege.is_a?(Privilege)
81
+ # no need to check anything if target is no Access Object
82
+ raise "target hast to be an AccessObject (#{target.class})" if target and !(target.class.respond_to?(:base_class) && ActiveAcl.is_access_object?(target.class))
83
+
84
+ active_acl_handler.has_privilege?(self,privilege,target)
85
+ end
86
+ def active_acl_handler
87
+ ActiveAcl.object_handler(self.class)
88
+ end
89
+ #returns a key value store
90
+ def active_acl_instance_cache
91
+ @active_acl_instance_cache ||= active_acl_handler.get_instance_cache(self)
92
+ end
93
+ #returns if the 2d acls are already cached
94
+ def active_acl_cached_2d?
95
+ !!active_acl_instance_cache[:prefetched_2d]
96
+ end
97
+ def active_acl_cached_2d!
98
+ active_acl_instance_cache[:prefetched_2d]=true
99
+ end
100
+
101
+ def active_acl_clear_cache!
102
+ @active_acl_instance_cache ={} #clear the lokal cache
103
+ active_acl_handler.delete_cached(self) #clear the 2 level cache
104
+ end
105
+ # override this to customize the description in the interface
106
+ def active_acl_description
107
+ to_s
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
113
+
114
+ ActiveRecord::Base.send(:include, ActiveAcl::Acts::AccessObject)