shioyama/mobility

Translated inputs are empty after failed form validation in a specific setup

Gert-JanPeeters opened this issue · 1 comments

When using translated attributes in forms, if the form validations fails (e.g. uniqueness off another attribute is not satisfied), the inputs of all the translated nested attributes are rendered empty.

Context

The issue explained above, only happens in forms where nested attributes are used that have a has_many relation and are displayed using the fields_for form helper.

For example, a product has many variants. The title of these variants is translatable. We want to change the title of these variants through the same form where we can change the attribute of the product. We use nested attributes and fields_for form helper:

<%= form_with model: @product do |form| %>
  <h1>Products</h1>
  <div class="form-row">
    <%= form.label :title %>
    <%= form.text_field :title %>
  </div>

  <div class="form-row">
    <%= form.label :handle %>
    <%= form.text_field :handle %>
  </div>

  <%= form.fields_for :variants do |variant| %>
    <h2>Variant</h2>
    <div class="form-row">
      <%= variant.label :title %>
      <%= variant.text_field :title %>
    </div>
  <% end %>

  <%= form.submit %>
<% end %>

If validation of this form fails for any reason, the variant.text_field is empty.

Expected Behavior

In the above case, we expect that the variant.text_field still shows the correct translation.

Actual Behavior

In the above case, the variant.text_field is empty. A similar problem happens when using form helper text_area instead of text_field.

You can find a repo with a fresh rails installation and an example of the problem here: https://github.com/frontierdotbe/translated-fields-empty-after-validation

Example (with pictures):
Screenshot 2023-01-11 at 11 22 48

In the handle, we fill in product. Because of this, validation fails, this causes the Variant title inputs to be empty.

Screenshot 2023-01-11 at 11 23 23

Possible Fix

In the above example, changing:

<%= variant.text_field :title %>

to:

<%= variant.text_field :title, value: variant.object.title %>

Solves the bug, however now we have to add value to every input which should not be necessary.

We believe the bug happens with the manipulation of value_before_type_cast that Mobility performs. Somehow, in the case of using fields_for in nested attributes (with a has_many relation), value_before_type_cast returns nil instead of value resulting into an empty input.

Thanks for the bug report. This is really beyond what Mobility is designed to handle out of the box. If you can figure out how to make this work, I'd be open to accepting a PR, but beyond that I can't really help.

We believe the bug happens with the manipulation of value_before_type_cast that Mobility performs.

I'm not sure what you're referring to, Mobility doesn't manipulate value_before_type_cast, it simply defines methods that fetch translated values.