Module: Ruact::Generators::ScaffoldGenerator::FormHelpers

Included in:
Ruact::Generators::ScaffoldGenerator
Defined in:
lib/generators/ruact/scaffold/scaffold_form_helpers.rb

Overview

Story 10.3 — the shadcn Form's view-model helpers: which @/components/ui/* primitives to import, the component's prop signature, and the references<Select> options sourcing (controller ivar → prop). Extracted into its own module to keep Ruact::Generators::ScaffoldGenerator within its class-length budget (mirrors the 10.2 ScaffoldAttribute extraction). Mixed in below the no_tasks boundary so these never register as Thor commands.

Constant Summary collapse

INPUT_SHADCN_CONTROLS =

The :input-family shadcn controls (all render an <Input>, varying only by type=); extracted so the predicate's array literal isn't rebuilt on every loop iteration.

%i[input number date datetime].freeze

Instance Method Summary collapse

Instance Method Details

#form_contract_propsObject

FR100 — the __ruactContract props object. EVERY prop the view may pass must be declared or the 13.5 call-site validator rejects it: initial plus each references options prop the new/edit views hand the Form. All optional (new omits initial; a reference-free Form omits options).



80
81
82
83
84
# File 'lib/generators/ruact/scaffold/scaffold_form_helpers.rb', line 80

def form_contract_props
  parts = ['initial: "optional"']
  parts += reference_attributes.map { |ref| %(#{ref.options_prop}: "optional") }
  "{ #{parts.join(', ')} }"
end

#form_props_paramsObject

The Form component's destructured props — initial plus one options prop per references field (authorOptions = []).



65
66
67
# File 'lib/generators/ruact/scaffold/scaffold_form_helpers.rb', line 65

def form_props_params
  ["initial = null"] + reference_attributes.map { |ref| "#{ref.options_prop} = []" }
end

#form_props_typeObject

FR99 — the Form component's prop type (typed mode only).



70
71
72
73
74
# File 'lib/generators/ruact/scaffold/scaffold_form_helpers.rb', line 70

def form_props_type
  parts = ["initial?: #{class_name}Row | null"]
  parts += reference_attributes.map { |ref| "#{ref.options_prop}?: { id: number; label: string }[]" }
  "{ #{parts.join('; ')} }"
end

#form_uses_input?Boolean

--- shadcn Form import predicates ------------------------------------ Emit only the @/components/ui/* imports the model's controls use, so a reference-free Form never imports Select, a textarea-free Form never imports Textarea, etc.

Returns:

  • (Boolean)


47
48
49
# File 'lib/generators/ruact/scaffold/scaffold_form_helpers.rb', line 47

def form_uses_input?
  scaffold_attributes.any? { |attr| INPUT_SHADCN_CONTROLS.include?(attr.shadcn_control) }
end

#form_uses_select?Boolean

Returns:

  • (Boolean)


59
60
61
# File 'lib/generators/ruact/scaffold/scaffold_form_helpers.rb', line 59

def form_uses_select?
  reference_attributes.any?
end

#form_uses_switch?Boolean

Returns:

  • (Boolean)


55
56
57
# File 'lib/generators/ruact/scaffold/scaffold_form_helpers.rb', line 55

def form_uses_switch?
  scaffold_attributes.any? { |attr| attr.shadcn_control == :switch }
end

#form_uses_textarea?Boolean

Returns:

  • (Boolean)


51
52
53
# File 'lib/generators/ruact/scaffold/scaffold_form_helpers.rb', line 51

def form_uses_textarea?
  scaffold_attributes.any? { |attr| attr.shadcn_control == :textarea }
end

#html_input_type(attr) ⇒ Object

The <Input type> for the :input-family controls (string→text, number, date, datetime→datetime-local). The shadcn <Input> forwards type to the native element, so the wire formats match for free.



89
90
91
92
93
94
95
96
# File 'lib/generators/ruact/scaffold/scaffold_form_helpers.rb', line 89

def html_input_type(attr)
  case attr.shadcn_control
  when :number then "number"
  when :date then "date"
  when :datetime then "datetime-local"
  else "text"
  end
end

#native_input_type(attr) ⇒ Object

Story 14.4 (FR103) — the native <input type> for the agnostic Form's input-family controls, mapped off the agnostic ScaffoldAttribute#control (TYPE_MAP) rather than the shadcn shadcn_control. boolean (:checkbox) and references (a <select>) are dispatched separately in the agnostic template, so this only resolves the text/number/date/datetime inputs.



103
104
105
106
107
108
109
110
# File 'lib/generators/ruact/scaffold/scaffold_form_helpers.rb', line 103

def native_input_type(attr)
  case attr.control
  when :number then "number"
  when :date then "date"
  when :datetime then "datetime-local"
  else "text"
  end
end

#reference_attributesObject

The references attributes — each renders a shadcn <Select> whose options the controller loads (ivar → prop). Empty for a reference-free model (the whole options path then stays inert).



21
22
23
# File 'lib/generators/ruact/scaffold/scaffold_form_helpers.rb', line 21

def reference_attributes
  scaffold_attributes.select(&:reference?)
end

#reference_options_expr(ref) ⇒ Object

Story 10.3 (AC6) — the controller expression loading a references field's options as plain { "id" =>, "label" => } row hashes (no as_json; the view passes them straight through as a prop). Labels fall back name → title → to_s. Capped at the threshold + 1 so the eager <Select> never balloons (a > threshold parent set wants the documented server-search combobox instead).



36
37
38
39
40
# File 'lib/generators/ruact/scaffold/scaffold_form_helpers.rb', line 36

def reference_options_expr(ref)
  label = "record.try(:name) || record.try(:title) || record.to_s"
  "#{ref.reference_class_name}.limit(#{reference_options_limit + 1})" \
    ".map { |record| { \"id\" => record.id, \"label\" => #{label} } }"
end

#reference_options_limitObject

The eager-options cap (template-friendly accessor for the constant).



26
27
28
# File 'lib/generators/ruact/scaffold/scaffold_form_helpers.rb', line 26

def reference_options_limit
  ScaffoldGenerator::REFERENCE_OPTIONS_LIMIT
end