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.



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

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.



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

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



82
83
84
# File 'lib/hibiki/rails/reactive_form.rb', line 82

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

#hibiki_modelObject



86
87
88
89
90
91
# File 'lib/hibiki/rails/reactive_form.rb', line 86

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_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.



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

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.



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

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.



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

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