Module: Hibiki::Rails::ReactiveForm::ClassMethods
- Defined in:
- lib/hibiki/rails/reactive_form.rb
Instance Method Summary collapse
-
#from(record) ⇒ Object
Hydrate from a record — the only supported constructor.
-
#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.
- #hibiki_attributes ⇒ Object
- #hibiki_model ⇒ Object
- #hibiki_nested ⇒ Object
-
#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.
-
#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. -
#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).
-
#reactive_attributes(model, *names) ⇒ Object
reactive_attributes Todo, :title, :done.
-
#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.
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_attributes ⇒ Object
96 97 98 |
# File 'lib/hibiki/rails/reactive_form.rb', line 96 def hibiki_attributes @hibiki_attributes || __hibiki_inherited(:hibiki_attributes) || [] end |
#hibiki_model ⇒ Object
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_nested ⇒ Object
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 |