Skip to content

Commit bec10dc

Browse files
joshuay03byroot
authored andcommitted
[Fix rails#33155] Set through target for new records
1 parent a4681cd commit bec10dc

File tree

4 files changed

+41
-0
lines changed

4 files changed

+41
-0
lines changed

activerecord/lib/active_record/associations/association.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,9 @@ def extensions
188188
# not reraised. The proxy is \reset and +nil+ is the return value.
189189
def load_target
190190
@target = find_target(async: false) if (@stale_state && stale_target?) || find_target?
191+
if !@target && set_through_target_for_new_record?
192+
@target = through_association.target.association(reflection.source_reflection_name).target
193+
end
191194

192195
loaded! unless loaded?
193196
target
@@ -321,6 +324,10 @@ def find_target?
321324
!loaded? && (!owner.new_record? || foreign_key_present?) && klass
322325
end
323326

327+
def set_through_target_for_new_record?
328+
owner.new_record? && reflection.through_reflection? && through_association.target
329+
end
330+
324331
# Returns true if there is a foreign key present on the owner which
325332
# references the target. This is used to determine whether we can load
326333
# the target if the owner is currently a new record (and therefore

activerecord/lib/active_record/associations/collection_association.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,14 @@ def include?(record)
272272
def load_target
273273
if find_target?
274274
@target = merge_target_lists(find_target, target)
275+
elsif target.empty? && set_through_target_for_new_record?
276+
@target = if through_reflection.collection?
277+
through_association.target.flat_map do |record|
278+
record.association(reflection.source_reflection_name).target
279+
end
280+
else
281+
through_association.target.association(reflection.source_reflection_name).target
282+
end
275283
end
276284

277285
loaded!

activerecord/test/cases/associations/has_many_through_associations_test.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,20 @@ def setup
5656
Reader.create person_id: 0, post_id: 0
5757
end
5858

59+
def test_setting_association_on_new_record_sets_through_records
60+
subscriber_1, subscriber_2 = Subscriber.create!(nick: "nick 1"), Subscriber.create!(nick: "nick 2")
61+
subscription_1 = Subscription.new(subscriber: subscriber_1)
62+
subscription_2 = Subscription.new(subscriber: subscriber_2)
63+
book = Book.new
64+
book.subscriptions = [subscription_1, subscription_2]
65+
66+
assert_predicate subscriber_1, :persisted?
67+
assert_predicate subscriber_2, :persisted?
68+
assert_predicate book, :new_record?
69+
book.subscriptions.each { |subscription| assert_predicate subscription, :new_record? }
70+
assert_equal book.subscribers.sort, [subscriber_1, subscriber_2].sort
71+
end
72+
5973
def test_has_many_through_create_record
6074
assert books(:awdr).subscribers.create!(nick: "bob")
6175
end

activerecord/test/cases/associations/has_one_through_associations_test.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,18 @@ def test_has_one_through_executes_limited_query
4343
end
4444
end
4545

46+
def test_setting_association_on_new_record_sets_through_record
47+
club = Club.create!
48+
membership = CurrentMembership.new(club: club)
49+
member = Member.new
50+
member.current_membership = membership
51+
52+
assert_predicate club, :persisted?
53+
assert_predicate member, :new_record?
54+
assert_predicate member.current_membership, :new_record?
55+
assert_equal club, member.club
56+
end
57+
4658
def test_creating_association_creates_through_record
4759
new_member = Member.create(name: "Chris")
4860
new_member.club = Club.create(name: "LRUG")

0 commit comments

Comments
 (0)