Using accepts_nested_attributes_for with assign_attributes means immediate saving of associated model

Previously raised at https://github.com/rails/rails/issues/17368

When a parent model accepts_nested_attributes_for a child, and you use assign_attributes on an existing parent, the children are immediately persisted; assign_attributes is just calling children= on the parent. This results in the changes being half-saved and messes things up if you wanted to do further processing before saving.

I propose that for has_one, has_many, and has_and_belongs_to_many associations, assign_attribute avoid persisting by instead:

  1. mark_for_destruction all existing children not present in the passed hash.
  2. Update (but not persist) all existing children present in the passed hash.
  3. Call children.build to create the new children.

I imagine this logic would go in _assign_attribute and would make use of reflect_on_association to figure out what’s what. I’d be willing to attempt to implement this, if it’s a change that would be desired.

1 Like

I think this would be a really good change and hope you decide to pursue it. The current behavior is not intuitive; one would expect that assign_attributes(nested_params) not persist any changes; if I wanted to persist changes I would use update(nested_params). I’ve been bitten by this and only after poring through the documentation realized why.

1 Like

May I bump this and stress that this is not just a nice to have or not intuitive. It’s a serious issue and even kind of dangerous. It’s been reported 5 years ago and it’s still a problem. Please review the Github thread or request further information so it can be fixed.

OR alternatively, clarify for whatever reason this might be “by design” or hint us at what we’re missing.

Thanks!

1 Like

Interesting. We’ve been raising a lot of improvement ideas this month, but this one truly sounds to me as a “WTF”.

“WTF” describes it quite nicely. :slightly_smiling_face:

Last year I worked on a PR to make make autosave optional for accepts_nested_attributes_for