rails icon indicating copy to clipboard operation
rails copied to clipboard

Eager load incorrectly sets 'through' associations on child objects

Open tttffff opened this issue 1 year ago • 1 comments

Steps to reproduce

Run in terminal

rails new nested_assoc && cd nested_assoc && rails g model Company name && \
rails g model Person company:belongs_to && rails g model Comment person:belongs_to parent:belongs_to

Make change to the create comments migration file

# t.belongs_to :parent, null: false, foreign_key: true
t.belongs_to :parent, null: true, foreign_key: { to_table: :comments }

Make change to comment model file

# belongs_to :parent
belongs_to :parent, class_name: 'Comment', optional: true
has_many :children, class_name: 'Comment', foreign_key: :parent_id
has_one :company, through: :person

Run in terminal

rails db:migrate && rails c

Run in rails console

airbnb = Company.create! name: 'Airbnb'
shopify = Company.create! name: 'Shopify'
alice = Person.create! company: airbnb
bob = Person.create! company: shopify
top_level_comment = Comment.create! person: alice
Comment.create! person: bob, parent: top_level_comment

Comment.first.children.first.company.name # Shopify, as expected
Comment.eager_load(children: :company).first.children.first.company.name # Shopify, as expected
Comment.eager_load(:company, children: :company).first.children.first.company.name # Airbnb!

Expected behavior

The child comment should have the Shopify company loaded.

Actual behavior

The child comment gets the company from the parent comment loaded.

System configuration

Rails version: 7.1.3.4

Ruby version: 3.2.3

tttffff avatar Jun 25 '24 23:06 tttffff

Note: when you do not use the through assosiation, it seems to work fine e.g.

Comment.eager_load(person: :company, children: {person: :company}).first.children.first.person.company.name

Gives the correct result, but all three:

Comment.eager_load(:company, children: {person: :company}).first.children.first.person.company.name
Comment.eager_load(person: :company, children: :company).first.children.first.company.name
Comment.eager_load(:company, children: :company).first.children.first.company.name

Will give the incorrect result. Using the through assosiation causes an issue if it is used for the eager load on the parent, child or both.

tttffff avatar Jun 25 '24 23:06 tttffff

This issue has been automatically marked as stale because it has not been commented on for at least three months. The resources of the Rails team are limited, and so we are asking for your help. If you can still reproduce this error on the 7-2-stable branch or on main, please reply with all of the information you have about it in order to keep the issue open. Thank you for all your contributions.

rails-bot[bot] avatar Sep 24 '24 12:09 rails-bot[bot]