Module: LcpRuby::Authorization::AssociationLookup

Defined in:
lib/lcp_ruby/authorization/association_lookup.rb

Overview

Reverse-resolves a parent model name to the ‘belongs_to` reflection on a child AR class. Used by `inherits_from` consumers (ScopeBuilder for the FK column, PermissionEvaluator for the association name, the InheritedParentValidator for both). Centralised so the polymorphic rejection rule and the multi-candidate ambiguity policy live in one place.

Defined Under Namespace

Classes: AmbiguousAssociation, MissingAssociation

Class Method Summary collapse

Class Method Details

.belongs_to_for(model_class, parent_name) ⇒ Object

Returns the matching belongs_to reflection or ‘nil` when no non-polymorphic belongs_to on `model_class` points at `parent_name`. Raises AmbiguousAssociation when more than one belongs_to qualifies (configurator must declare `via:` explicitly in that case).



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/lcp_ruby/authorization/association_lookup.rb', line 19

def belongs_to_for(model_class, parent_name)
  candidates = model_class
               .reflect_on_all_associations(:belongs_to)
               .reject { |r| r.options[:polymorphic] }
               .select { |r| r.class_name.demodulize.underscore == parent_name.to_s }

  case candidates.size
  when 0 then nil
  when 1 then candidates.first
  else
    raise AmbiguousAssociation,
          "inherits_from #{parent_name}: multiple belongs_to point to " \
          "#{parent_name} on #{model_class.name} — declare `via:` explicitly"
  end
end

.belongs_to_for!(model_class, parent_name) ⇒ Object

Same as ‘belongs_to_for` but raises MissingAssociation when no association qualifies. For consumers that require a definite answer.



37
38
39
40
41
42
# File 'lib/lcp_ruby/authorization/association_lookup.rb', line 37

def belongs_to_for!(model_class, parent_name)
  belongs_to_for(model_class, parent_name) ||
    raise(MissingAssociation,
          "inherits_from #{parent_name}: no belongs_to on " \
          "#{model_class.name} points to #{parent_name}")
end

.belongs_to_name_for(model_class, parent_name) ⇒ Object

Returns the association name as a symbol, or ‘nil` if no match.



45
46
47
# File 'lib/lcp_ruby/authorization/association_lookup.rb', line 45

def belongs_to_name_for(model_class, parent_name)
  belongs_to_for(model_class, parent_name)&.name
end

.foreign_key_for(model_class, parent_name) ⇒ Object

Returns the foreign-key column name as a string. Raises MissingAssociation when no belongs_to qualifies.



51
52
53
# File 'lib/lcp_ruby/authorization/association_lookup.rb', line 51

def foreign_key_for(model_class, parent_name)
  belongs_to_for!(model_class, parent_name).foreign_key
end