Flowdock

Good notes posted by drogus

RSS feed
April 8, 2009
13 thanks

Setting 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.