What I am trying to do is namespace a custom-made object in a dyamically-built form by passing it to fields_for. The object is not an ActiveRecord model and I am doing my best to make it quack like one with minimal effort.
Everything works with the exception of the "field_with_errors" wrapper which does not get added. Any ideas on how to make that part work?
I have a form which submits data to FormResponses model and runs its validations. Once the validations are run, the form_response
object contains the namespaced form data as well as errors:
[1] pry(#<#<Class:0x007fe743c64418>>)> form_response
=> #<FormResponse:0x007fe74d30aa98
id: nil,
data: {"name_prefix"=>"Mr.", "first_name"=>"", "middle_initial"=>"", "last_name"=>"", "name_suffix"=>"", "title"=>""},
form_id: 2,
created_at: nil,
updated_at: nil>
[2] pry(#<#<Class:0x007fe743c64418>>)> form_response.errors
=> #<ActiveModel::Errors:0x007fe74d309080
@base=
#<FormResponse:0x007fe74d30aa98
id: nil,
data: {"name_prefix"=>"Mr.", "first_name"=>"", "middle_initial"=>"", "last_name"=>"", "name_suffix"=>"", "title"=>""},
form_id: 2,
created_at: nil,
updated_at: nil>,
@messages={:will_attend=>["Please indicate your attendance"], :first_name=>["Please provide your first name"]}>
# this is what I pass to the form_for builder
[3] pry(#<#<Class:0x007fe743c64418>>)> form_response.form_data
=> #<OpenStruct name_prefix="Mr.", first_name="", middle_initial="", last_name="", name_suffix="", title="">
I display this object in the following way:
form.html.slim
= form_for form_response, url: "", authenticity_token: false, html: {class: "form"} do |ff|
= hidden_field_tag "authenticity_token", csrf_token
= ff.hidden_field "_prefilled_status", value: is_prefilled.prefilled
= ff.hidden_field "_prefilled_condition", value: is_prefilled.condition
= fields_for :form_data, form_response.form_data do |f|
= ff.hidden_field "form_id", value: form_response.form_id
# form_components holds the form field tree data which lets us create the form dynamically
- form_components.each do |component|
= render partial: "./#{component.kind}", locals: { f: f, component: component }
having each of the fields processed by a partial corresponding to the field type, for example:
_text.html.slim
li class=component.container_css
= f.label component.field_name, component.label, class: concat_and_trim('desc', component.required_class)
span = f.text_field component.field_name, component.tag_options_with_css
The issue is that the fields created with f.field_name do not get the "field_with_errors" wrapper when errors are present.
Given that the errors are on the form_response active record model passed on to the "ff" form builder, shouldn't they trigger the wrapping on the form_for objects?
The form_for fields retainthe submitted values if I include form_response.form_data which contains the form field values submitted under the form_data namespace, like this:
= fields_for :form_data, form_response.form_data do |f|
If I omit the form_response.form_data part, the fields get cleared on submit
= fields_for :form_data do |f|
Which means that the fields_for uses that information to prefill the fields. How do I pass the error information to fields_for so that the fields get the error class wrapper?