How to submit multiple NEW items via Rails 3.2 mass-assignment

As others have mentioned, the [] should contain a key for new records because otherwise it is mixing a hash with an array type. You can set this with the child_index option on fields_for.

f.fields_for :items, Item.new, child_index: "NEW_ITEM" # ...

I usually do this using the object_id instead to ensure it is unique in case there are multiple new items.

item = Item.new
f.fields_for :items, item, child_index: item.object_id # ...

Here’s an abstract helper method that does this. This assumes there is a partial with the name of item_fields which it will render.

def link_to_add_fields(name, f, association)
  new_object = f.object.send(association).klass.new
  id = new_object.object_id
  fields = f.fields_for(association, new_object, child_index: id) do |builder|
    render(association.to_s.singularize + "_fields", f: builder)
  end
  link_to(name, '#', class: "add_fields", data: {id: id, fields: fields.gsub("\n", "")})
end

You can use it like this. The arguments are: the name of the link, the parent’s form builder, and the name of the association on the parent model.

<%= link_to_add_fields "Add Item", f, :items %>

And here is some CoffeeScript to listen to the click event of that link, insert the fields, and update the object id with the current time to give it a unique key.

jQuery ->
  $('form').on 'click', '.add_fields', (event) ->
    time = new Date().getTime()
    regexp = new RegExp($(this).data('id'), 'g')
    $(this).before($(this).data('fields').replace(regexp, time))
    event.preventDefault()

That code is taken from this RailsCasts Pro episode which requires a paid subscription. However, there is a full working example freely available on GitHub.

Update: I want to point out that inserting a child_index placeholder is not always necessary. If you do not want to use JavaScript to insert new records dynamically, you can build them up ahead of time:

def new
  @project = Project.new
  3.times { @project.items.build }
end

<%= f.fields_for :items do |builder| %>

Rails will automatically insert an index for the new records so it should just work.

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)