Module: Plutonium::Wizard::FieldImporter

Defined in:
lib/plutonium/wizard/field_importer.rb

Overview

Resolves a step's using: option (§2.4) — importing a field surface from a model (ActiveRecord class) instead of re-declaring it.

using: targets a model only. A Plutonium::Resource::Definition carries no link to its model (it's an empty class the controller binds at request time), so the only reliable direction is model → definition: the importer auto-resolves "#{Model}Definition" to overlay input styling, best-effort.

The imported surface is:

- **attribute_schema** ({name => type}) — the field universe is
`Model.attribute_names` (filtered by selectors); types are
`Model.attribute_types[name].type`.
- **inputs** ({name => {options:, block:}}) — overlaid from the resolved
`<Model>Definition`'s `field`/`input` config (`as:`, options, labels),
sliced to the imported names. No definition → empty input config.
- **form_layout** — the resolved `<Model>Definition`'s `defined_form_layout`,
filtered to the imported fields, **plus a trailing ungrouped section** for
imported fields not named in any explicit section (skipped when
`layout: false`).
- **validate_fn** — runs a transient `Model.new(slice).valid?` and keeps
errors only on the imported fields **plus `:base`** (skipped when
`validate: false`).

Validation is run-and-filtered rather than cloned: AR validators can't be cloned cleanly. Filtering to imported fields + :base is what prevents a partial model reporting presence errors for columns this step never collects.

Defined Under Namespace

Classes: Spec

Constant Summary collapse

FORM_VALIDATOR_KINDS =

The validator kinds the form pipeline reads for field metadata (required marker, maxlength/minlength, min/max, pattern, auto-choices). Other kinds (uniqueness, custom EachValidators) carry no form meaning, so we skip them — and replaying a custom kind through validates would raise.

%i[presence length numericality format inclusion].freeze

Class Method Summary collapse

Class Method Details

.resolve(using:, opts:) ⇒ Spec

Parameters:

  • using (Class)

    an ActiveRecord model class

  • opts (Hash)

    fields:/only:/except:/validate:/layout:/validation_context:

Returns:



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/plutonium/wizard/field_importer.rb', line 52

def resolve(using:, opts:)
  model = model!(using)
  opts ||= {}
  only = normalize(opts[:fields] || opts[:only])
  except = normalize(opts[:except]) || []
  do_validate = opts.fetch(:validate, true)
  do_layout = opts.fetch(:layout, true)
  context = opts[:validation_context]

  names = select(model.attribute_names.map(&:to_sym), only:, except:)
  definition = "#{model.name}Definition".safe_constantize

  schema = names.index_with { |n| record_type(model, n) }

  validate_fn = build_validate(do_validate) do |slice|
    record = model.new(string_slice(slice, names))
    run_and_filter(record, names, context)
  end

  Spec.new(
    attribute_schema: schema,
    inputs: inputs_for(definition, names),
    form_layout: do_layout ? layout_for(definition, names) : nil,
    validate_fn:,
    form_validators: form_validators_for(model, names)
  )
end