class Eaco::DSL::ACL
Block-less DSL
to set up the {ACL} machinery onto an authorized {Resource}.
-
Defines an {ACL} subclass in the
Resource
namespace ({#define_acl_subclass}) -
Defines syntactic sugar on the
ACL
to easily retrieve {Actor}s with a specific Role ({#define_role_getters}) -
Installs {ACL} objects persistance for the supported ORMs ({#install_persistance})
-
Installs the authorized collection extraction strategy
.accessible_by
({#install_strategy})
Public Class Methods
Private Instance Methods
Tries to identify which ORM adapter to use for the target
class.
@return [Class] the adapter implementation or nil if not available.
# File lib/eaco/dsl/acl.rb, line 156 def adapter { 'ActiveRecord::Base' => Eaco::Adapters::ActiveRecord, 'CouchRest::Model::Base' => Eaco::Adapters::CouchrestModel, }.fetch(orm.name, nil) end
Creates the ACL
constant on the target, inheriting from {Eaco::ACL}. Removes if it is already set, so that a reload of the authorization rules refreshes also these constants.
The ACL
subclass can be retrieved using the .acl
singleton method on the {Resource} class.
@return [void]
# File lib/eaco/dsl/acl.rb, line 51 def define_acl_subclass target_eval do remove_const(:ACL) if const_defined?(:ACL, false) Class.new(Eaco::ACL).tap do |acl_class| define_singleton_method(:acl) { acl_class } const_set(:ACL, acl_class) end end end
Define getter methods on the ACL
for each role, syntactic sugar for calling {ACL#find_by_role}.
Example:
If a reader
role is defined, allows doing resource.acl.readers
and returns all the designators having the reader
role set.
@return [void]
# File lib/eaco/dsl/acl.rb, line 73 def define_role_getters roles = self.target.roles target.acl.instance_eval do roles.each do |role| define_method(role.to_s.pluralize) { find_by_role(role) } end end end
Sets up the persistance layer for ACLs (#acl
and #acl=
).
These APIs can be implemented directly in your Resource
model, as long as the acl
accessor accepts and returns the Resource
model's ACL
subclass (see {.define_acl_subclass})
See each adapter for the details of the extraction strategies they provide.
@return [void]
# File lib/eaco/dsl/acl.rb, line 95 def install_persistance if adapter target.send(:include, adapter) install_authorized_collection_strategy elsif (target.instance_methods & [:acl, :acl=]).size != 2 raise Malformed, <<-EOF Don't know how to persist ACLs using <#{target}>'s ORM (identified as <#{orm}>). Please define an `acl' instance accessor on <#{target}> that accepts and returns a <#{target.acl}>. EOF end end
Sets up the authorized collection extraction strategy (.accessible_by
).
This API can be implemented directly in your model, as long as .accessible_by
returns an Enumerable
collection.
@return [void]
# File lib/eaco/dsl/acl.rb, line 118 def install_strategy unless target.respond_to?(:accessible_by) strategies = adapter ? adapter.strategies.keys : [] raise Malformed, <<-EOF Don't know how to look up authorized records on <#{target}>'s ORM (identified as <#{orm}>). To authorize <#{target}> #{ if strategies.size > 0 "either use one of the available strategies: #{strategies.join(', ')} or" end } please define your own #{target}.accessible_by method. You may at one point want to move this in a new strategy, and send a pull request :-). EOF end end
Tries to naively identify which ORM the target model is using.
TODO support more stuff
@return [Class] the ORM base class.
# File lib/eaco/dsl/acl.rb, line 169 def orm if defined?(ActiveRecord::Base) && target.ancestors.include?(ActiveRecord::Base) ActiveRecord::Base else target.superclass # Naive end end