提交 1f8534ca 编写于 作者: R Ryuta Kamizono

Fix `AssociationRelation` not to set inverse instance key just like before

Since #31575, `set_inverse_instance` replaces the foreign key by the
current owner immediately to make it happen when a record is added to
collection association.

But `set_inverse_instance` is not only called when a record is added,
but also when a record is loaded from queries. And also, that loaded
records are not always associated records for some reason (using `or`,
`unscope`, `rewhere`, etc).

It is hard to distinguish whether or not we should invoke
`set_inverse_instance`, but at least we should avoid the undesired
side-effect which was brought from #31575.

Fixes #34108.
上级 651d8743
......@@ -31,9 +31,9 @@ def create!(*args, &block)
private
def exec_queries
super do |r|
@association.set_inverse_instance r
yield r if block_given?
super do |record|
@association.set_inverse_instance_from_queries(record)
yield record if block_given?
end
end
end
......
......@@ -103,6 +103,13 @@ def set_inverse_instance(record)
record
end
def set_inverse_instance_from_queries(record)
if inverse = inverse_association_for(record)
inverse.inversed_from_queries(owner)
end
record
end
# Remove the inverse association, if possible
def remove_inverse_instance(record)
if inverse = inverse_association_for(record)
......@@ -114,6 +121,7 @@ def inversed_from(record)
self.target = record
@inversed = !!record
end
alias :inversed_from_queries :inversed_from
# Returns the class of the target. belongs_to polymorphic overrides this to look at the
# polymorphic_type field on the owner.
......
......@@ -2356,6 +2356,18 @@ def test_collection_association_with_private_kernel_method
assert_equal [accounts(:signals37)], firm.accounts.open
end
def test_association_with_or_doesnt_set_inverse_instance_key
firm = companies(:first_firm)
accounts = firm.accounts.or(Account.where(firm_id: nil)).order(:id)
assert_equal [firm.id, nil], accounts.map(&:firm_id)
end
def test_association_with_rewhere_doesnt_inverse_instance_key
firm = companies(:first_firm)
accounts = firm.accounts.rewhere(firm_id: [firm.id, nil]).order(:id)
assert_equal [firm.id, nil], accounts.map(&:firm_id)
end
test "first_or_initialize adds the record to the association" do
firm = Firm.create! name: "omg"
client = firm.clients_of_firm.first_or_initialize
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册