Module: Hibiki::Rails::ReactiveForm::ClassMethods

Defined in:
lib/hibiki/rails/reactive_form.rb

Instance Method Summary collapse

Instance Method Details

#from(record) ⇒ Object

Hydrate from a record — the only supported constructor. Extra arguments are forwarded to #initialize, so a form with its own constructor still works.



52
# File 'lib/hibiki/rails/reactive_form.rb', line 52

def from(record, ...) = new(...).hydrate(record)

#hibiki_association_type(name) ⇒ Object

The ids cast for a reactive_association: the target model's primary-key type, resolved on every use like hibiki_model so a reload can't pin a stale class.



126
127
128
129
130
131
# File 'lib/hibiki/rails/reactive_form.rb', line 126

def hibiki_association_type(name)
  reflection = hibiki_model.reflect_on_association(name)
  raise "#{hibiki_model} has no #{name} association" if reflection.nil?

  reflection.klass.type_for_attribute(reflection.klass.primary_key)
end

#hibiki_attributesObject



96
97
98
# File 'lib/hibiki/rails/reactive_form.rb', line 96

def hibiki_attributes
  @hibiki_attributes || __hibiki_inherited(:hibiki_attributes) || []
end

#hibiki_modelObject



100
101
102
103
104
105
# File 'lib/hibiki/rails/reactive_form.rb', line 100

def hibiki_model
  model = @hibiki_model || __hibiki_inherited(:hibiki_model)
  raise "#{self} has no reactive_attributes declaration" if model.nil?

  model.is_a?(Module) ? model : model.to_s.constantize
end

#hibiki_nestedObject



107
108
109
# File 'lib/hibiki/rails/reactive_form.rb', line 107

def hibiki_nested
  @hibiki_nested || __hibiki_inherited(:hibiki_nested) || {}
end

#hibiki_nested_form(name) ⇒ Object

The child form class, resolved on every use like hibiki_model so a String declaration never pins a constant across a reload.



113
114
115
116
# File 'lib/hibiki/rails/reactive_form.rb', line 113

def hibiki_nested_form(name)
  form = hibiki_nested.fetch(name)
  form.is_a?(Module) ? form : form.to_s.constantize
end

#hibiki_type(name) ⇒ Object

Channel action params arrive as strings; casting through the model's own attribute type is the difference between done = "false" meaning false and meaning true.



121
# File 'lib/hibiki/rails/reactive_form.rb', line 121

def hibiki_type(name) = hibiki_model.type_for_attribute(name.to_s)

#reactive_association(*names) ⇒ Object

reactive_association :tags — an ids signal (tag_ids) over a collection association, declared AFTER reactive_attributes (the target comes off the model's reflection). Hydrate reads the model's own collection-ids reader and commit hands the ids to #update, where AR's association writer does the join-row bookkeeping — so the macro only owns the signal and its cast: each id goes through the TARGET model's primary-key type, and the multi-select hidden-input blank is dropped.



77
78
79
80
81
# File 'lib/hibiki/rails/reactive_form.rb', line 77

def reactive_association(*names)
  raise "#{self}: declare reactive_attributes before reactive_association" unless __hibiki_model_declared?

  names.each { |name| __hibiki_ids_signal(name) }
end

#reactive_attributes(model, *names) ⇒ Object

reactive_attributes Todo, :title, :done

The model may be a Class or a String/Symbol; a name is resolved on every use, so a form class under app/ never pins a constant across a Zeitwerk reload.



59
60
61
62
63
64
65
66
67
# File 'lib/hibiki/rails/reactive_form.rb', line 59

def reactive_attributes(model, *names)
  @hibiki_model = model
  @hibiki_attributes = names.map(&:to_sym)
  casts = __hibiki_casts
  @hibiki_attributes.each do |name|
    state name
    casts.define_method(:"#{name}=") { |value| super(self.class.hibiki_type(name).cast(value)) }
  end
end

#reactive_nested(name, form_class) ⇒ Object

reactive_nested :steps, "StepForm" — a signal holding an array of child forms over an accepts_nested_attributes_for association. #to_h serializes it as steps_attributes, so #commit persists the whole tree in the record's own save. The child form class may itself declare reactive_nested — depth is composition, nothing here counts levels. Deliberately NOT in hibiki_attributes: that stays the scalar allowlist for set_field/assign-style code.



90
91
92
93
94
# File 'lib/hibiki/rails/reactive_form.rb', line 90

def reactive_nested(name, form_class)
  name = name.to_sym
  @hibiki_nested = { **hibiki_nested, name => form_class }
  state(name) { [] }
end