0

I'm using simple_nested_form_for to build a form with nested fields. Fields are added dynamically

When rendering the form with errors (via create) the nested fields go wrong.

The same nested fields are shown multiple times and with the wrong index values in the name elements.

For example the FormBuilder index in the nested field is initially a random number such as 1454793731550. After re-rendering they simply become normal increments 0-n.

Why is the FormBuilder index initially a random number?

Any suggestion what could be going on here?

  def new
    @transaction = current_company.transactions.build
    @transaction.subtransactions.build
  end

  def create
    @transaction = current_company.transactions.new(transaction_params)

    if @transaction.save
      redirect_to dashboard_url
    else
      @transaction.subtransactions.build
       render :action => 'new'
    end
Nishi
  • 10,634
  • 3
  • 27
  • 36
Matthias
  • 1,884
  • 2
  • 18
  • 35
  • You're going to need to post the code from your view before anybody can provide any useful insight. – Jon Feb 06 '16 at 22:03

1 Answers1

1

The index is the child_index of the nested fields. This is simply a way for Rails to individually identify the various field names of the HTML form elements:

<%= f.fields_for :association do |a| %>
  <%= a.text_field :x %> #-> "child_index" id will either be sequential (0,1,2)
<% end %>

The child_index doesn't matter. As long as it's unique, it should be passed to the controller as follows:

params: {
  association_attributes: {
    0: { x: "y", z: "0" },
    1: { ... }
  }
}

A trick often used is to set the child_index to Time.now.to_i, which allows you to add new fields out of scope:

<%= f.fields_for :association, child_index: Time.now.to_i do |a| %>

In regards your new action with the likely issue is that your subtransactions object is being built each time (irrespective of whether the instance is populated with previous data).

We've had this issue before, and I believe that we solved it with a conditional:

def new
  @transaction = current_company.transactions.build
  @transaction.subtransactions.build unless @transaction.errors.any?

This should maintain the object's integrity through the submission process. IE if an error occurs, I believe Rails stores the associated object in memory (like it does with the parent).

Community
  • 1
  • 1
Richard Peck
  • 76,116
  • 9
  • 93
  • 147
  • Hi Richard, thanks for explaining to me about the `child-index` to `Time.now.to_s`. Very useful! Adding `unless @transaction.errors.any?` to my `new` action seems to have fixed the problem. Conceptually, however I do not get this. Why does a conditional statement about errors in the new action influence what is executed after submission through `create`? – Matthias Feb 08 '16 at 16:41