Module: LcpRuby::Authorization::IncludesHint
- Defined in:
- lib/lcp_ruby/authorization/includes_hint.rb
Overview
Builds an ‘ActiveRecord::Relation#includes` argument that preloads the parent associations along an `inherits_from` cascade. Composes recursively so a 3-tier chain `grade → student → school_class` yields `{ student: { school_class: {} } }` — preloading just the immediate parent is not enough when the parent’s own scope traverses further.
The hint is purely additive: AR’s ‘.includes` is associative and idempotent, so callers may chain their own `.includes(…)` on top (e.g. presenter-driven `IncludesResolver`) and the result is one consolidated preload graph.
See ‘docs/design/hierarchical_record_permissions.md` § 6.7 (Increment 3 of hierarchical record permissions).
Class Method Summary collapse
-
.build(scope_spec, model_class, roles, depth = 0) ⇒ Object
Returns one of: nil — scope has no inheritance to preload Hash — ‘{ assoc: <child> }` per parent (always a Hash for the `inherits` branch) Array — top-level `union` of multiple branches; AR accepts mixed `[:a, { b: :c }]`.
Class Method Details
.build(scope_spec, model_class, roles, depth = 0) ⇒ Object
Returns one of:
nil — scope has no inheritance to preload
Hash — `{ assoc: <child> }` per parent (always a Hash for
the `inherits` branch)
Array — top-level `union` of multiple branches; AR accepts
mixed `[:a, { b: :c }]`.
‘model_class` is the AR class the scope spec applies to (needed to resolve the `belongs_to` reflection name from the parent model name — handles `via:` overrides via `AssociationLookup`).
‘roles` is the list already computed by the caller (`PermissionEvaluator#roles`) — passed through so we don’t re-walk the role resolver per parent and so the unit specs can drive the helper without a real ‘User`.
Bounded by ‘max_inheritance_depth` (also enforced by `ConfigurationValidator#detect_inheritance_cycle` at boot) so a malformed cycle here cannot loop forever.
39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/lcp_ruby/authorization/includes_hint.rb', line 39 def build(scope_spec, model_class, roles, depth = 0) return nil unless scope_spec.is_a?(Hash) return nil if depth > LcpRuby.configuration.max_inheritance_depth case scope_spec["type"] when "inherits" build_inherits(scope_spec, model_class, roles, depth) when "union" build_union(scope_spec, model_class, roles, depth) end end |