Class: Authorization::ObligationScope
- Inherits:
-
ActiveRecord::Relation
- Object
- ActiveRecord::Relation
- Authorization::ObligationScope
- Defined in:
- lib/declarative_authorization/obligation_scope.rb
Overview
The ObligationScope
class parses any number of obligations into joins and conditions.
In ObligationScope
parlance, “association paths” are one-dimensional arrays in which each element represents an attribute or association (or “step”), and “leads” to the next step in the association path.
Suppose we have this path defined in the context of model Foo: { :bar => { :baz => { :foo => { :attr => is { user } } } } }
To parse this path, ObligationScope
evaluates each step in the context of the preceding step. The first step is evaluated in the context of the parent scope, the second step is evaluated in the context of the first, and so forth. Every time we encounter a step representing an association, we make note of the fact by storing the path (up to that point), assigning it a table alias intended to match the one that will eventually be chosen by ActiveRecord when executing the find
method on the scope.
+@table_aliases =
[] => 'foos',
[:bar] => 'bars',
[:bar, :baz] => 'bazzes',
[:bar, :baz, :foo] => 'foos_bazzes' # Alias avoids collisions with 'foos' (already used)
+
At the “end” of each path, we expect to find a comparison operation of some kind, generally comparing an attribute of the most recent association with some other value (such as an ID, constant, or array of values). When we encounter a step representing a comparison, we make note of the fact by storing the path (up to that point) and the comparison operation together. (Note that individual obligations’ conditions are kept separate, to allow their conditions to be OR’ed together in the generated scope options.)
+@obligation_conditions[[:bar, :baz, :foo]] = [
[ :attr, :is, <user.id> ]
]+
TODO update doc for Relations: After successfully parsing an obligation, all of the stored paths and conditions are converted into scope options (stored in proxy_options
as :joins
and :conditions
). The resulting scope may then be used to find all scoped objects for which at least one of the parsed obligations is fully met.
@proxy_options = { :bar => { :baz => :foo } } @proxy_options = [ ‘foos_bazzes.attr = :foos_bazzes__id_0’, { :foos_bazzes__id_0 => 1 } ]
Instance Method Summary collapse
-
#initialize(model, options) ⇒ ObligationScope
constructor
A new instance of ObligationScope.
-
#parse!(obligation) ⇒ Object
Consumes the given obligation, converting it into scope join and condition options.
- #scope ⇒ Object
Constructor Details
#initialize(model, options) ⇒ ObligationScope
Returns a new instance of ObligationScope.
46 47 48 49 50 |
# File 'lib/declarative_authorization/obligation_scope.rb', line 46 def initialize(model, ) @finder_options = {} super(model, table: model.table_name) end |
Instance Method Details
#parse!(obligation) ⇒ Object
Consumes the given obligation, converting it into scope join and condition options.
58 59 60 61 62 63 64 65 66 |
# File 'lib/declarative_authorization/obligation_scope.rb', line 58 def parse!( obligation ) @current_obligation = obligation @join_table_joins = Set.new obligation_conditions[@current_obligation] ||= {} follow_path( obligation ) end |
#scope ⇒ Object
52 53 54 55 |
# File 'lib/declarative_authorization/obligation_scope.rb', line 52 def scope # TODO Refactor this. There is certainly a better way. self.klass.joins(@finder_options[:joins]).includes(@finder_options[:include]).where(@finder_options[:conditions]).references(@finder_options[:include]) end |