Good notes posted by drogus
RSS feedSetting child_index while using nested attributes mass assignment
When using nested attributes mass assignment sometimes you will want to add new records with javascript. You can do it with pure javascript, but if HTML is long your javascript will be long and messy and it will not be DRY as probably you already have a partial for it.
So to add a partial dynamically you can do something like that (notice string “index_to_replace_with_js”):
link_to_function
def add_object_link(name, form, object, partial, where) options = {:parent => true}.merge(options) html = render(:partial => partial, :locals => { :form => form}, :object => object) link_to_function name, %{ var new_object_id = new Date().getTime() ; var html = jQuery(#{js html}.replace(/index_to_replace_with_js/g, new_object_id)).hide(); html.appendTo(jQuery("#{where}")).slideDown('slow'); } end
js method in one of helpers (from minus mor plugin)
def js(data) if data.respond_to? :to_json data.to_json else data.inspect.to_json end end
This method will generate link adding generated partial to html.
The thing that is not mentioned in docs is how to set child_index. You must add it as an argument in hash.
Example of partial
<% form.fields_for :tasks, task, :child_index => (task.new_record? ? "index_to_replace_with_js" : nil) do |tasks_form| %> <% tasks_form.text_field :name %> <% end %>
Using add_object_link
<% form_for :project do |form| %> <div id="tasks"> <%# displaying existing tasks %> </div> <%= add_object_link("New task, form, Task.new, "task", "#tasks") %> <% end %>
Thanks to child_index after insertion it will change indexes to current time in miliseconds so added tasks will have different names and ids.