I'm using nested fields and accept nested attributes with a 3 level nested relationship. The 3rd level (I don't think it matters that it's third level) relationship gets deleted when editing the parent.
Setup has one material, material has one rotap_analysis, rotap_analysis has many rotap_sieves. The following code is what triggers the delete ONLY WHEN EDITING AN EXISTING SETUP THAT ALREADY HAS A ROTAP ANALYSIS, creating new or editing and creating new rotap analysis works fine:
<%= f.fields_for :rotap_analysis do |ra| %>
<%= render 'materials/rotap_analysis_fields', f: ra %>
<% end %>
<div class="links float-e-margins">
<!-- this is deleting rotap analysis -->
<%= link_to_add_association '+ rotap analysis', f, :rotap_analysis, partial: 'materials/rotap_analysis_fields', class: "btn btn-info btn-xs" %>
</div>
Here is the server log with the delete transactions upon rendering with "fields_for" helper.
RotapAnalysis Load (0.3ms) SELECT "rotap_analyses".* FROM "rotap_analyses" WHERE "rotap_analyses"."material_id" = $1 LIMIT $2 [["material_id", 23], ["LIMIT", 1]]
↳ app/views/materials/_material_fields.html.erb:77
RotapSieve Load (4.2ms) SELECT "rotap_sieves".* FROM "rotap_sieves" WHERE "rotap_sieves"."rotap_analysis_id" = $1 [["rotap_analysis_id", 18]]
↳ app/views/materials/_rotap_analysis_fields.html.erb:24
Rendered materials/_rotap_sieve_fields.html.erb (Duration: 1.0ms | Allocations: 488)
Rendered materials/_rotap_sieve_fields.html.erb (Duration: 0.9ms | Allocations: 475)
Rendered materials/_rotap_analysis_fields.html.erb (Duration: 13.0ms | Allocations: 2823)
TRANSACTION (0.3ms) BEGIN
↳ app/views/materials/_material_fields.html.erb:82
RotapSieve Destroy (0.4ms) DELETE FROM "rotap_sieves" WHERE "rotap_sieves"."id" = $1 [["id", 17]]
↳ app/views/materials/_material_fields.html.erb:82
RotapAnalysis Destroy (0.5ms) DELETE FROM "rotap_analyses" WHERE "rotap_analyses"."id" = $1 [["id", 18]]
↳ app/views/materials/_material_fields.html.erb:82
TRANSACTION (1.0ms) COMMIT
↳ app/views/materials/_material_fields.html.erb:82
Rendered materials/_rotap_sieve_fields.html.erb (Duration: 0.9ms | Allocations: 475)
Rendered materials/_rotap_analysis_fields.html.erb (Duration: 4.2ms | Allocations: 1495)
Rendered materials/_material_fields.html.erb (Duration: 43.9ms | Allocations: 12427)
Rendered setups/_form.html.erb (Duration: 123.8ms | Allocations: 42184)
Rendered setups/edit.html.erb within layouts/application (Duration: 124.1ms | Allocations: 42245
I have several nested attributes throughout the application and I have never ran into this issue. What the heck is going on?
As documented this is weird but well known behaviour when using a has_one
relationship. By default cocoon uses the association to create the new nested item.
But then rails assumes, if you already have one, creating a new one will replace it (which does make sense).
However: when using the link_to_add_association
we pre-create an empty item to fill, so it will always delete it.
There is a simple workaround: for has_one
associations you can use the force_non_association_create: true
which will not create the child element using the association, and thus will not remove existing items (for has_one
associations).
So in your case you would write:
<%= link_to_add_association '+ rotap analysis', f, :rotap_analysis,
partial: 'materials/rotap_analysis_fields',
force_non_association_create: true,
class: "btn btn-info btn-xs" %>