Using fields_for can generate invalid HTML
Just a quick post so show you how fields_for form helper can cause invalid HTML when used in combination with accepts_nested_attributes_for in your views.
If you are for any reason editing/creating your child objects in a tabular form, your view might look something like this:
<% form_for(@todo_list) do |f| %><%= f.label :name %><%= f.text_field :name %><h3>To Do Items:</h3><table><thead><tr><th>To Do Item</th><th>Due Date</th><th>Done?</th></tr></thead><tbody><% f.fields_for :items do |item| %><tr><td><%= item.text_field :content %></td><td><%= item.text_field :due_date %></td><td><%= item.check_box :done %></td></tr><% end %></tbody></table><%= f.submit 'Save' %><% end %>
At first glance this looks fine. However, when the ToDoList model has accepts_nested_attributes_for :items, the fields_for helper also outputs a hidden field for each existing Item instance with it’s ID.
This means that we get the following HTML:
<form action="/to_do_lists/1" class="edit_to_do_list" id="edit_to_do_list_1" method="post"><div style="margin:0;padding:0;display:inline"><input name="_method" type="hidden" value="put" /><input name="authenticity_token" type="hidden" value="CE2jyRoewbwsqu4eX8AFWFqsgrMfCN35Jzy6b43MhsA=" /></div><label for="to_do_list_name">Name</label><input id="to_do_list_name" name="to_do_list[name]" size="30" type="text" value="Sup" /><h3>To Do Items:</h3><table><thead><tr><th>To Do Item</th><th>Due Date</th><th>Done?</th></tr></thead><tbody><input id="to_do_list_items_attributes_0_id" name="to_do_list[items_attributes][0][id]" type="hidden" value="1" /><tr><td><input id="to_do_list_items_attributes_0_content" name="to_do_list[items_attributes][0][content]" size="30" type="text" value="arst" /></td><td><input id="to_do_list_items_attributes_0_due_date" name="to_do_list[items_attributes][0][due_date]" size="30" type="text" value="2009-07-30" /></td><td><input name="to_do_list[items_attributes][0][done]" type="hidden" value="0" /><input id="to_do_list_items_attributes_0_done" name="to_do_list[items_attributes][0][done]" type="checkbox" value="1" /></td></tr><input id="to_do_list_items_attributes_1_id" name="to_do_list[items_attributes][1][id]" type="hidden" value="2" /><tr><td><input id="to_do_list_items_attributes_1_content" name="to_do_list[items_attributes][1][content]" size="30" type="text" value="arst" /></td><td><input id="to_do_list_items_attributes_1_due_date" name="to_do_list[items_attributes][1][due_date]" size="30" type="text" value="2009-07-30" /></td><td><input name="to_do_list[items_attributes][1][done]" type="hidden" value="0" /><input id="to_do_list_items_attributes_1_done" name="to_do_list[items_attributes][1][done]" type="checkbox" value="1" /></td></tr></tbody></table><input id="to_do_list_submit" name="commit" type="submit" value="Save" /></form>
The keen eye will notice the hidden <input> tags that are direct children of the tbody:
<tbody><input id="to_do_list_items_attributes_0_id" name="to_do_list[items_attributes][0][id]" type="hidden" value="1" /><tr><!-- clip! --></tr><input id="to_do_list_items_attributes_1_id" name="to_do_list[items_attributes][1][id]" type="hidden" value="2" /><tr><!-- clip! --></tr></tbody>
This is not a valid place for an <input> tag.
I’ve put an example project demonstrating this on my GitHub