Fix has_many assocation w/select load after create #7859

Merged
merged 1 commit into from Oct 10, 2012

3 participants

@ernie

If you create a new record via a collection association proxy that has
not loaded its target, and which selects additional attributes through
the association, then when the proxy loads its target, it will
inadvertently trigger an ActiveModel::MissingAttributeError during
attribute writing when CollectionAssociation#merge_target_lists attempts
to do its thing, since the newly loaded records will possess attributes
the created record does not.

This error also raises a bogus/confusing deprecation warning when
accessing the association in Rails 3.2.x, so cherry-pick would be
appreciated!

@ernie ernie Fix has_many assocation w/select load after create
If you create a new record via a collection association proxy that has
not loaded its target, and which selects additional attributes through
the association, then when the proxy loads its target, it will
inadvertently trigger an ActiveModel::MissingAttributeError during
attribute writing when CollectionAssociation#merge_target_lists attempts
to do its thing, since the newly loaded records will possess attributes
the created record does not.

This error also raises a bogus/confusing deprecation warning when
accessing the association in Rails 3.2.x, so cherry-pick would be
appreciated!
9f3b8cd
@ernie

Quick note: an alternative (but slightly more cumbersome to implement) fix might be to detect those loaded records which possess attributes the in-memory versions don't have, and swap the attribute replacement out to the changes from the in-memory version. I'm working on that fix now.

@ernie

On second thought, no I'm not. That has some pretty serious drawbacks, in that the object would no longer be the same instance as the one that the user may have received as a return from the call to create.

@rafaelfranca
Ruby on Rails member

@tenderlove could you take a look?

@tenderlove
Ruby on Rails member
@tenderlove tenderlove was assigned Oct 6, 2012
@ernie

Aloha, @tenderlove! I've been thinking about this and as much as I really wish there was a good way for an in-memory record to have identical attributes to those read through the association, the use case would be sufficiently rare that the solution here is probably "good enough."

Internal AR calls shouldn't be raising errors/deprecations (depending on version) that were intended to reflect changes being necessary to user code, so this patch avoids that. Swapping out the in-memory object for its from-disk counterpart would be bad for the reasons I mentioned the other day, and trying to step around the write_attribute protection against creating new attributes on an existing object (to use the in-memory version but graft on the additional attributes) is painful enough that I think the code is trying to tell us we'd be nuts to do it.

@tenderlove
Ruby on Rails member

@ernie ok! I'll merge as-is then! Thanks.

@tenderlove tenderlove merged commit 269adae into rails:master Oct 10, 2012
@ernie

@tenderlove Thanks! Any chance it could get cherry-picked to 3-2-stable as well? It doesn't raise an error there, but generates a bogus deprecation message:

DEPRECATION WARNING: You're trying to create an attribute `some_attribute'. Writing arbitrary attributes on a model is deprecated. Please just use `attr_writer` etc. (called from some_method at /some_file:5)
@ernie

Or, if you want, I can work out a test for 3-2-stable and submit a separate PR

@rafaelfranca
Ruby on Rails member

@ernie please submit a pull request

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment