Fix nullification of has_many :through association with `query_constraints #47721
+20
−2
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Given a
has_many :through
association withquery_constraints
:It is possible to nullify the association like
blog_post.tags = []
which results in deletion of records from the
posts_tags
joining table.Implementation details
The test we added fails on main with
NoMethodError: undefined method to_sym for ["blog_id", "id"]:Array
on the linerails/activerecord/lib/active_record/associations/through_association.rb
Line 66 in d53dc86
However this failure is misleading as we shouldn't be reaching this line at all, at least for the test we built.
In our case the issue lies a few lines above, at:
rails/activerecord/lib/active_record/associations/through_association.rb
Line 62 in d53dc86
Since the introduction of
query_constraints
in associationsassociation_primary_key
can be an array whileprimary_key
may not necessarily be an array in case if the model uses virtualquery_constraints
definition. So essentially we need to compareassociation_primary_key
withquery_constraints_list
if it is not empty and only then compare it with a primary key. To avoid branching I've introduced a new internal concept -composite_query_constraints_list
this is an always non-empty array of query constraints that either equals to manually configuredquery_constraints
or to theprimary_key
wrapped in an array. This concept will be useful in the future in internal codeplaces that are ready to work with an array of columns to avoid unnecessary branching.After comparing primary keys as Arrays the logic follows into the branch and queries the records by the association name which has already been fixed in #47692
We still need to address the
else
branch but for this we will need to extend ourSharded
fixtures to have an association with a customsource_type
orquery_constraints:
configuration different from the parent'squery_constraints