Module: LcpRuby::Metadata::FieldPath
- Defined in:
- lib/lcp_ruby/metadata/field_path.rb
Overview
Walks a dot-path field reference through metadata to find the terminal field definition and its owning model name.
Used by view templates and helpers that need to humanize/route an enum value coming from a cross-model field path like ‘“contact.tier”` or `“order.customer.status”`. The terminal model_name is the i18n namespace under which `enum_label_for` should look up labels (`lcp_ruby.enums.<model>.<field>.*`).
Returns ‘[FieldDefinition, model_name]` or `[nil, nil]` when:
- model_def is nil or path is blank
- any intermediate segment is missing / non-LCP
- an intermediate segment is a collection (`has_many`) and
`through_collections:` is false (the default)
- any segment cannot be loaded from the metadata loader
‘through_collections:` — when false (default), an intermediate `has_many` aborts the walk (`[nil, nil]`). This is what `LabelMethodBuilder` wants: a `to_label` walks a singular chain with `public_send`, so a collection mid-path can’t yield a scalar value. Display surfaces (index tables, cards, tree) pass ‘true`: a has_many terminal enum (e.g. `contacts.tier`) resolves to an Array of values that the field def still humanizes element-wise (issue #18). The terminal field def is identical either way — the flag only governs whether a collection mid-path is allowed.
Callers treat ‘[nil, nil]` as “no metadata available — pass through”.
Class Method Summary collapse
Class Method Details
.terminal(model_def, path, through_collections: false) ⇒ Object
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/lcp_ruby/metadata/field_path.rb', line 33 def terminal(model_def, path, through_collections: false) return [ nil, nil ] if model_def.nil? path_str = path.to_s return [ nil, nil ] if path_str.empty? parts = path_str.split(".") current_def = model_def parts[0..-2].each do |segment| assoc = current_def.associations.find { |a| a.name == segment } return [ nil, nil ] unless assoc&.lcp_model? return [ nil, nil ] unless through_collections || assoc.singular? current_def = LcpRuby.loader.model_definition(assoc.target_model) return [ nil, nil ] if current_def.nil? end [ current_def.field(parts.last), current_def.name ] rescue MetadataError [ nil, nil ] end |