Skip to content

Commit

Permalink
Merge pull request rails#53869 from joshuay03/handle-nested-through-t…
Browse files Browse the repository at this point in the history
…arget-setting-for-new-records

Handle setting of nested through records for new records
  • Loading branch information
byroot authored Dec 9, 2024
2 parents 7e06191 + 4283228 commit 5520bd8
Show file tree
Hide file tree
Showing 7 changed files with 56 additions and 7 deletions.
9 changes: 8 additions & 1 deletion activerecord/lib/active_record/associations/association.rb
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,14 @@ def extensions
def load_target
@target = find_target(async: false) if (@stale_state && stale_target?) || find_target?
if !@target && set_through_target_for_new_record?
@target = through_association.target.association(reflection.source_reflection_name).target
reflections = reflection.chain
reflections.pop
reflections.reverse!

@target = reflections.reduce(through_association.target) do |middle_target, reflection|
break unless middle_target
middle_target.association(reflection.source_reflection_name).target
end
end

loaded! unless loaded?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -273,12 +273,18 @@ def load_target
if find_target?
@target = merge_target_lists(find_target, target)
elsif target.empty? && set_through_target_for_new_record?
@target = if through_reflection.collection?
through_association.target.flat_map do |record|
record.association(reflection.source_reflection_name).target
reflections = reflection.chain
reflections.pop
reflections.reverse!

@target = reflections.reduce(through_association.target) do |middle_target, reflection|
if middle_target.empty?
break []
elsif reflection.collection?
middle_target.flat_map { |record| record.association(reflection.source_reflection_name).target }
else
middle_target.association(reflection.source_reflection_name).target
end
else
through_association.target.association(reflection.source_reflection_name).target
end
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
require "models/zine"
require "models/interest"
require "models/human"
require "models/account"

class HasManyThroughAssociationsTest < ActiveRecord::TestCase
fixtures :posts, :readers, :people, :comments, :authors, :categories, :taggings, :tags,
Expand All @@ -67,7 +68,24 @@ def test_setting_association_on_new_record_sets_through_records
assert_predicate subscriber_2, :persisted?
assert_predicate book, :new_record?
book.subscriptions.each { |subscription| assert_predicate subscription, :new_record? }
assert_equal book.subscribers.sort, [subscriber_1, subscriber_2].sort
assert_equal [subscriber_1, subscriber_2].sort, book.subscribers.sort
end

def test_setting_association_on_new_record_sets_nested_through_records
account_1 = Account.create!(firm_name: "account 1", credit_limit: 100)
subscriber_1 = Subscriber.create!(nick: "nick 1", account: account_1)
account_2 = Account.create!(firm_name: "account 2", credit_limit: 100)
subscriber_2 = Subscriber.create!(nick: "nick 2", account: account_2)
subscription_1 = Subscription.new(subscriber: subscriber_1)
subscription_2 = Subscription.new(subscriber: subscriber_2)
book = Book.new
book.subscriptions = [subscription_1, subscription_2]

assert_predicate subscriber_1, :persisted?
assert_predicate subscriber_2, :persisted?
assert_predicate book, :new_record?
book.subscriptions.each { |subscription| assert_predicate subscription, :new_record? }
assert_equal [account_1, account_2].sort, book.subscriber_accounts.sort
end

def test_has_many_through_create_record
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,20 @@ def test_setting_association_on_new_record_sets_through_record
assert_equal club, member.club
end

def test_setting_association_on_new_record_sets_nested_through_record
category = Category.create!(name: "General")
club = Club.create!(category: category)
membership = CurrentMembership.new(club: club)
member = Member.new
member.current_membership = membership

assert_predicate category, :persisted?
assert_predicate club, :persisted?
assert_predicate member, :new_record?
assert_predicate member.current_membership, :new_record?
assert_equal club.category, member.club_category
end

def test_creating_association_creates_through_record
new_member = Member.create(name: "Chris")
new_member.club = Club.create(name: "LRUG")
Expand Down
1 change: 1 addition & 0 deletions activerecord/test/models/book.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ class Book < ActiveRecord::Base

has_many :subscriptions
has_many :subscribers, through: :subscriptions
has_many :subscriber_accounts, through: :subscribers, source: :account

has_one :essay

Expand Down
2 changes: 2 additions & 0 deletions activerecord/test/models/subscriber.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
class Subscriber < ActiveRecord::Base
self.primary_key = "nick"

belongs_to :account

has_many :subscriptions
has_many :books, through: :subscriptions
end
Expand Down
1 change: 1 addition & 0 deletions activerecord/test/schema/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1173,6 +1173,7 @@
t.integer :books_count, null: false, default: 0
t.integer :update_count, null: false, default: 0
t.index :nick, unique: true
t.references :account
end

create_table :subscriptions, force: true do |t|
Expand Down

0 comments on commit 5520bd8

Please sign in to comment.