khagimoto
2009-Aug-01 01:09 UTC
Form problem with three layer deep "accepts_nested_attributes_for"
Hello, I''m going to borrow this (http://gist.github.com/53464) example, since my model is set up exactly the same way. I''m trying to build a form that will add as many Parent to a GrandParent and as many Child to a Parent as user wants in a nested form. It work if I only have one parent and multiple children. As soon as I add more than one parent, the problem starts. I have partials for both parent and child, where child partial gets included in the parent partial with "form.fields_for" call. In the helper, I have methods to add/remove parent or child at will. Something like this: ======================================= def add_parent_link(form_builder) link_to_function ''Add More parent'' do |page| form_builder.fields_for :parents, Parent.new, :child_index => ''NEW_RECORD'' do |f| html = render(:partial => ''parent'', :locals => { :form => f }) page << "$(''parents'').insert({ bottom: ''#{escape_javascript (html)}''.replace(/NEW_RECORD/g, new Date().getTime()) });" end end end def remove_trip_region_link(form_builder) if form_builder.object.new_record? link_to_function("Remove this Region", "$(this).up (''.more_regions'').remove();"); else form_builder.hidden_field(:_delete) + link_to_function("Remove this Region", "$(this).up (''.more_regions'').hide(); $(this).previous().value = ''1''") end end ======================================= The problem is that the child form gets messed up since it''s inside the parent form and (I think) "escape_javascript" is done twice on it. Has anyone encountered this type of problem? If so, what was your solution? Thanks!
Josh White
2009-Aug-01 19:22 UTC
Re: Form problem with three layer deep "accepts_nested_attributes_for"
I thin to help you I would need to see the params that show up in the log from the post request and your controller logic which saves it. On Jul 31, 6:09 pm, khagimoto <kumi.hagim...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> Hello, > > I''m going to borrow this (http://gist.github.com/53464) example, since > my model is set up exactly the same way. > I''m trying to build a form that will add as many Parent to a > GrandParent and as many Child to a Parent as user wants in a nested > form. It work if I only have one parent and multiple children. As > soon as I add more than one parent, the problem starts. > > I have partials for both parent and child, where child partial gets > included in the parent partial with "form.fields_for" call. In the > helper, I have methods to add/remove parent or child at will. > Something like this: > > =======================================> def add_parent_link(form_builder) > link_to_function ''Add More parent'' do |page| > form_builder.fields_for :parents, Parent.new, :child_index => > ''NEW_RECORD'' do |f| > html = render(:partial => ''parent'', :locals => { :form => f }) > page << "$(''parents'').insert({ bottom: ''#{escape_javascript > (html)}''.replace(/NEW_RECORD/g, new Date().getTime()) });" > end > end > end > > def remove_trip_region_link(form_builder) > if form_builder.object.new_record? > link_to_function("Remove this Region", "$(this).up > (''.more_regions'').remove();"); > else > form_builder.hidden_field(:_delete) + > link_to_function("Remove this Region", "$(this).up > (''.more_regions'').hide(); $(this).previous().value = ''1''") > end > end > =======================================> > The problem is that the child form gets messed up since it''s inside > the parent form and (I think) "escape_javascript" is done twice on it. > > Has anyone encountered this type of problem? If so, what was your > solution? > Thanks!
khagimoto
2009-Aug-02 20:28 UTC
Re: Form problem with three layer deep "accepts_nested_attributes_for"
I actually never get to that point.... This is a problem that I see on screen when I load the page before submitting the nested form. The "Add More Parent" (and "Remove this Parent") links are created by the helper method below. =======================================def add_parent_link(form_builder) link_to_function ''Add More parent'' do |page| form_builder.fields_for :parents, Parent.new, :child_index => ''NEW_RECORD'' do |f| html = render(:partial => ''parent'', :locals => { :form => f }) page << "$(''parents'').insert({ bottom: ''#{escape_javascript (html)}''.replace(/NEW_RECORD/g, new Date().getTime()) });" end end end def remove_parent_link(form_builder) if form_builder.object.new_record? link_to_function("Remove this Parent", "$(this).up (''.more_parents'').remove();"); else form_builder.hidden_field(:_delete) + link_to_function("Remove this Parent", "$(this).up(''.more_parents'').hide(); $(this).previous ().value = ''1''") end end ======================================= When I first load the page with the three-layer nested form, everything looks fine with one parent and one child of it showing up. I can even "add more child" to the initially visible parent form. Problem occurs when I "Add more Parent". When the next parent is added, I see one parent with mangled child form. And I think that is because the child form goes through the helper method twice - one method is the "add_parent_link" shown above and the other is "add_child_link" (not shown, but does exactly the same as "add_parent_link"). I hope I''m making sense here.. I''m hoping that I don''t have to do this with two separate form-submits, but maybe that''s what I have to do.. :-( Thanks!
kikan
2009-Aug-13 16:13 UTC
Re: Form problem with three layer deep "accepts_nested_attributes_for"
Hi,> Problem occurs when I "Add more Parent". When the next parent is > added, I see one parent with mangled child form. And I think that is > because the child form goes through the helper method twice - one > method is the "add_parent_link" shown above and the other is > "add_child_link" (not shown, but does exactly the same as > "add_parent_link"). I hope I''m making sense here.I run into the same problem. I tried to pass an option "already_escaping" set to true if I add_parent_link is called from a partial which was already called add_parent_link. And then, I used the options like this : if options[:already_escaping]!=true html = escape_javascript(html) end I even rewrote the escape_javascript to become "unescape_javascript" like this : JS_UNESCAPE_MAP = { ''\\\\'' => ''\\'', ''<\/'' => ''</'', ''\n'' => "\r\n", ''\n'' => "\n" , ''\n'' => "\r" , ''\\"'' => ''"'' , "\\''" => "''" } def unescape_javascript(javascript) if javascript javascript.gsub(/(\\\\|<\\\/|\\\n|\\"|\\''|\n)/) { JS_UNESCAPE_MAP [$1] } else '''' end end But still without success. I think what''s important is to understand what''s beeing called and when. The children partial seems to be rendered while contructing the parent one. When it''s rendered, the Javascript is escaped. And then when the parent is rendered, the Javascript is escaped once again. Tell me if I''m wrong. It''s not a solution to the problem, but maybe seeing it from our two points of vue will help us find a solution :-) The methods in my helper are like this : def helper_remove_link(fields) out = '''' out << fields.hidden_field(:_delete) out << link_to_function("Supprimer", "$(this).up(''.# {fields.object.class.name.underscore}'').hide(); $(this).previous ().value = ''1''") out end def helper_add_record_link(form_builder, method, caption, options {}) options[:object] ||form_builder.object.class.reflect_on_association(method).klass.new options[:partial] ||= method.to_s.singularize options[:form_builder_local] ||= :f options[:insert] ||= method link_to_function(caption) do |page| form_builder.fields_for(method, options[:object], :child_index => ''NEW_RECORD'') do |f| html = render(:partial => options[:partial], :locals => { options[:form_builder_local] => f }) if options[:already_escaping]!=true html = escape_javascript(html) end page << %{ $(''#{options[:insert]}'').insert({ bottom: ''#{html}''.replace(/NEW_RECORD/g, new Date ().getTime()) }); } end end end And I call the helper like this, to add a children : <%= helper_add_record_link f, :contacts, ''Ajouter un contact...'', :insert => "#{prefix}contacts_#{f.object.id ? f.object.id : ''NEW_RECORD'' }", :already_escaping => true %> Best regards, Christian