Dynamically adding child field on form as described in Railscast 197 does not use :child_index parameter to generate html name attribute
I have an application where I 开发者_开发知识库am trying to add records as shown in the Railscast number 197. My objects are more simple, as I only have one level of Parent/child relationships: Patients and events. The code works fine for removing a child record (events), but adding a record fails for the following reason. I am able to create a new Object, generate the fields to display on the form, and the form looks ok. However the :child_index is missing from the name attribute in the generated html. An example of the html generated is:
<textarea cols="30" id="patient_events_attributes_description" name="patient[events_attributes][description]" rows="3"></textarea>
The html of an existing record is:
<textarea cols="30" id="patient_events_attributes_1_description" name="patient[events_attributes][1][description]" rows="3">Opgepakt met gestolen goederen</textarea>
Note that the [1] in the existing record is missing in the new html. Of course it should not be 1, but new_xxx which is then replaced by a unique number. But the whole [new_xxx] is missing in the generated html. Does anyone have an idea of what is wrong?
I am using Ruby 1.9.2, with Rails 3.0.10. I have only JQuery with no prototype, or query-ujs.
The code I'm using is shown here below, but it is a copy of the Railscast code:
def link_to_remove_fields(name, f)
f.hidden_field(:_destroy) + link_to_function(name, "remove_fields(this)")
end
def link_to_add_fields(name, f, association)
new_object = f.object.class.reflect_on_association(association).klass.new
fields = f.fields_for(association, new_object, :child_index => "new_#{association}") do |builder| # new_#{association}
render(association.to_s.singularize + "_fields", :f => builder)
end
link_to_function(name, "add_fields(this, \"#{association}\", \"#{escape_javascript(fields)}\")")
end
function remove_fields(link) {
$(link).prev("input[type=hidden]").val = "1";
$(link).closest(".fields").hide();
}
function add_fields(link, association, content) {
alert(content);
var new_id = new Date().getTime();
var regexp = new RegExp("new_" + association, "g");
$(link).before(content.replace(regexp, new_id));
}
i haven't been able to find any other comments that this code does not work, so I must be doing something very wrong. Any ideas out there?
After looking at the source code for fields_for, I found the two problems: 1. The :child_index parameter is not used, instead of that the :index option is used. 2. fields_for only generates the correct html if the object passed is an active record object, or an array. I changed the parameter passed to type array, with the new blank object as the [0] entry.
It is remarkable that there is no documentation of this feature. It makes ROR very time consuming to use, unless you were born there.
The code that finally works is as follows. Note that the '99' must be replace with a unique number if more records are to be added.
I still haven't go it completely working as the @patient.update_attributes(params[:patient]) gives some errors, but the worst part (adding the html) is fixed.
def link_to_add_fields(name, g, association)
new_object = []
new_object[0] = g.object.class.reflect_on_association(association).klass.new
fields = g.fields_for(association, new_object, :index => '99') do |builder| # , {:child_index => "new_#{association}"} new_#{association}
render(association.to_s.singularize + "_fields", :f => builder)
end
link_to_function(name, "add_fields(this, \"#{association}\", \"#{escape_javascript(fields)}\")")
end
精彩评论