Skip to content

Commit 5520bd8

Browse files
authored
Merge pull request rails#53869 from joshuay03/handle-nested-through-target-setting-for-new-records
Handle setting of nested through records for new records
2 parents 7e06191 + 4283228 commit 5520bd8

File tree

7 files changed

+56
-7
lines changed

7 files changed

+56
-7
lines changed

activerecord/lib/active_record/associations/association.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,14 @@ def extensions
189189
def load_target
190190
@target = find_target(async: false) if (@stale_state && stale_target?) || find_target?
191191
if !@target && set_through_target_for_new_record?
192-
@target = through_association.target.association(reflection.source_reflection_name).target
192+
reflections = reflection.chain
193+
reflections.pop
194+
reflections.reverse!
195+
196+
@target = reflections.reduce(through_association.target) do |middle_target, reflection|
197+
break unless middle_target
198+
middle_target.association(reflection.source_reflection_name).target
199+
end
193200
end
194201

195202
loaded! unless loaded?

activerecord/lib/active_record/associations/collection_association.rb

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -273,12 +273,18 @@ def load_target
273273
if find_target?
274274
@target = merge_target_lists(find_target, target)
275275
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
276+
reflections = reflection.chain
277+
reflections.pop
278+
reflections.reverse!
279+
280+
@target = reflections.reduce(through_association.target) do |middle_target, reflection|
281+
if middle_target.empty?
282+
break []
283+
elsif reflection.collection?
284+
middle_target.flat_map { |record| record.association(reflection.source_reflection_name).target }
285+
else
286+
middle_target.association(reflection.source_reflection_name).target
279287
end
280-
else
281-
through_association.target.association(reflection.source_reflection_name).target
282288
end
283289
end
284290

activerecord/test/cases/associations/has_many_through_associations_test.rb

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
require "models/zine"
4242
require "models/interest"
4343
require "models/human"
44+
require "models/account"
4445

4546
class HasManyThroughAssociationsTest < ActiveRecord::TestCase
4647
fixtures :posts, :readers, :people, :comments, :authors, :categories, :taggings, :tags,
@@ -67,7 +68,24 @@ def test_setting_association_on_new_record_sets_through_records
6768
assert_predicate subscriber_2, :persisted?
6869
assert_predicate book, :new_record?
6970
book.subscriptions.each { |subscription| assert_predicate subscription, :new_record? }
70-
assert_equal book.subscribers.sort, [subscriber_1, subscriber_2].sort
71+
assert_equal [subscriber_1, subscriber_2].sort, book.subscribers.sort
72+
end
73+
74+
def test_setting_association_on_new_record_sets_nested_through_records
75+
account_1 = Account.create!(firm_name: "account 1", credit_limit: 100)
76+
subscriber_1 = Subscriber.create!(nick: "nick 1", account: account_1)
77+
account_2 = Account.create!(firm_name: "account 2", credit_limit: 100)
78+
subscriber_2 = Subscriber.create!(nick: "nick 2", account: account_2)
79+
subscription_1 = Subscription.new(subscriber: subscriber_1)
80+
subscription_2 = Subscription.new(subscriber: subscriber_2)
81+
book = Book.new
82+
book.subscriptions = [subscription_1, subscription_2]
83+
84+
assert_predicate subscriber_1, :persisted?
85+
assert_predicate subscriber_2, :persisted?
86+
assert_predicate book, :new_record?
87+
book.subscriptions.each { |subscription| assert_predicate subscription, :new_record? }
88+
assert_equal [account_1, account_2].sort, book.subscriber_accounts.sort
7189
end
7290

7391
def test_has_many_through_create_record

activerecord/test/cases/associations/has_one_through_associations_test.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,20 @@ def test_setting_association_on_new_record_sets_through_record
5555
assert_equal club, member.club
5656
end
5757

58+
def test_setting_association_on_new_record_sets_nested_through_record
59+
category = Category.create!(name: "General")
60+
club = Club.create!(category: category)
61+
membership = CurrentMembership.new(club: club)
62+
member = Member.new
63+
member.current_membership = membership
64+
65+
assert_predicate category, :persisted?
66+
assert_predicate club, :persisted?
67+
assert_predicate member, :new_record?
68+
assert_predicate member.current_membership, :new_record?
69+
assert_equal club.category, member.club_category
70+
end
71+
5872
def test_creating_association_creates_through_record
5973
new_member = Member.create(name: "Chris")
6074
new_member.club = Club.create(name: "LRUG")

activerecord/test/models/book.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ class Book < ActiveRecord::Base
99

1010
has_many :subscriptions
1111
has_many :subscribers, through: :subscriptions
12+
has_many :subscriber_accounts, through: :subscribers, source: :account
1213

1314
has_one :essay
1415

activerecord/test/models/subscriber.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
class Subscriber < ActiveRecord::Base
44
self.primary_key = "nick"
55

6+
belongs_to :account
7+
68
has_many :subscriptions
79
has_many :books, through: :subscriptions
810
end

activerecord/test/schema/schema.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1173,6 +1173,7 @@
11731173
t.integer :books_count, null: false, default: 0
11741174
t.integer :update_count, null: false, default: 0
11751175
t.index :nick, unique: true
1176+
t.references :account
11761177
end
11771178

11781179
create_table :subscriptions, force: true do |t|

0 commit comments

Comments
 (0)