nested_form_fields icon indicating copy to clipboard operation
nested_form_fields copied to clipboard

Templates break when nesting inside a regular Rails fields_for

Open jensljungblad opened this issue 8 years ago • 7 comments

I'm having some trouble with deeply nested form fields. It works fine when nesting only using nested_fields_for but if I add a regular fields_for in between, the generated <script> template tag breaks.

form_for @resource do |f|
  f.nested_fields_for :foo do |ff|
    ff.fields_for :bar do |fff|
      fff.nested_fields_for :baz do |ffff|
        # stuff
      end
    end
  end
end

In this case, bar is a belongs_to relation on foo, which means I cannot use nested_fields_for which expects a relation.

jensljungblad avatar May 03 '16 10:05 jensljungblad

Looks like you used the wrong builders in the nested forms. I think it should be:

form_for @resource do |f|
  f.nested_fields_for :foo do |ff|
    ff.fields_for :bar do |fff|
      fff.nested_fields_for :baz do |ffff|
        # stuff
      end
    end
  end
end

ncri avatar May 03 '16 11:05 ncri

Oops, that was a typo from my end. Now the question should be corrected. The problem persists. We're looking into if the for_template option gets lost along the way somehow.

jensljungblad avatar May 03 '16 11:05 jensljungblad

I haven't tested this case yet. I can look into it as soon as I have some time. Let me know if you find the issue. ;-)

ncri avatar May 03 '16 11:05 ncri

It works with the following changes:

form_for @resource do |f|
  f.nested_fields_for :foo do |ff|
    ff.fields_for :bar do |fff|
      fff.nested_fields_for :baz, for_template: true do |ffff|
        # stuff
      end
    end
  end
end

That is, we pass along for_template

def nested_model_template name, association_name, options, block
  for_template = options[:for_template] || self.options[:for_template]

Not sure if this is a workable way to solve it?

We also couldn't find where self.options[:for_template] is actually saved. Is it a Rails thing?

jensljungblad avatar May 03 '16 11:05 jensljungblad

Actually, if you set for_template on fields_for instead, it will pass it along and things seem to work. So no change needed?

form_for @resource do |f|
  f.nested_fields_for :foo do |ff|
    ff.fields_for :bar, for_template: true do |fff|
      fff.nested_fields_for :baz do |ffff|
        # stuff
      end
    end
  end
end

jensljungblad avatar May 03 '16 11:05 jensljungblad

Okay, good, but it is a hack :) for_template is an internal option only. Hm. I'd like to find a better solution. But might be tricky.

ncri avatar May 03 '16 12:05 ncri

Probably to do this cleanly we will have to patch fields_for to pass down the for_template option from the parent builder... But glad you found a workaround. Although, more correct would probably be:

form_for @resource do |f|
  f.nested_fields_for :foo do |ff|
    ff.fields_for :bar, for_template: ff.options[:for_template] do |fff|
      fff.nested_fields_for :baz do |ffff|
        # stuff
      end
    end
  end
end

Because for_template should only be true when the form is rendered as a nested form fields template.

ncri avatar May 05 '16 11:05 ncri