ActiveRecord: Nested :include erroneous behavior

Hi,
Found a simple example breaking on moving to 2.2 from 2.0. This
example illustrates the usage of nested :include finder options.

class Book < ActiveRecord::Base
  has_many :distributors
end

class Distributor < ActiveRecord::Base
  belongs_to :book
  has_many :agents
end

class Agent < ActiveRecord::Base
  belongs_to :distributor
  has_many :shops
end

class Shop < ActiveRecord::Base
  belongs_to :agent
end

Schema - http://pastie.org/426261

def test_should_load_avatars
  shop_1= Shop.create!
  shop_2= Shop.create!
  book= Book.create!(:distributors => [Distributor.create!(:agents=>
[Agent.create!(:shops => [shop_2, shop_2])])])

  loaded_version = Book.find(book.id, :include => [:distributors =>
{:agents => :shops}], :order => 'shops.id')

  assert(loaded_version.distributors.first.agents.first.shops.size ==
2) #THIS ASSERTION FAILS WITH SHOPS.SIZE BEING 1, INSTEAD OF 2
end

On some investigation, I found that the query fired was correct, but
Rails was unable to instantiate the 'shops' collection properly.

Any help on this issue would be appreciated.

Thanks

def test_should_load_avatars
shop_1= Shop.create!
shop_2= Shop.create!
book= Book.create!(:distributors => [Distributor.create!(:agents=>
[Agent.create!(:shops => [shop_2, shop_2])])])

loaded_version = Book.find(book.id, :include => [:distributors =>
{:agents => :shops}], :order => 'shops.id')

assert(loaded_version.distributors.first.agents.first.shops.size ==
2) #THIS ASSERTION FAILS WITH SHOPS.SIZE BEING 1, INSTEAD OF 2
end

On some investigation, I found that the query fired was correct, but
Rails was unable to instantiate the 'shops' collection properly.

The problem is not to do with the nested-ness of the includes but
because you have an agent with the same shop twice (the line in
question that removes duplicates is
http://github.com/rails/rails/blob/f97832b1e4406a76d268a96b521d2297adec0ae3/activerecord/lib/active_record/associations.rb#L1781

Fred

Bad paste. The problem again. Looks like it is a problem only when there is a has_one relationship.

class Book < ActiveRecord::Base
has_one :distributor
end

class Distributor < ActiveRecord::Base
belongs_to :book
has_many :agents
end

class Agent < ActiveRecord::Base
belongs_to :distributor
has_many :shops
end

class Shop < ActiveRecord::Base
belongs_to :agent
end

Schema - http://pastie.org/426261

def test_should_load_avatars
shop_1= Shop.create!
shop_2= Shop.create!
book= Book.create!(:distributor => Distributor.create!(:agents=> [Agent.create!(:shops => [shop_1, shop_2])]))

loaded_version = Book.find(book.id, :include => [:distributor => {:agents => :shops}], :order => ‘shops.id’)

assert(loaded_version.distributor.agents.first.shops.size == 2)
#THIS ASSERTION FAILS WITH SHOPS.SIZE BEING 1, INSTEAD OF 2
end

This fails on Rails 2.2.2.
Any help on this would be much appreciated,
Akshay

Created a ticket for this issue at - http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/2341

Bad paste. The problem again. Looks like it is a problem only when there is
a has_one relationship.

Do you need all these models/associations or is there a small test
case that fails ?

Fred

Thanks for looking at it.

A one file test - http://pastie.org/426840

Another thing I saw was that the that test passes when :include is replaced with :joins.

Thanks for looking at it.A one file test -http://pastie.org/426840

Another thing I saw was that the that test passes when :include is replaced
with :joins.

Not surprising - in that case the association isn't eager loaded at
all. If it passes without the order clause then you've narrowed it
down to the joins based include mechanism.

Fred

Yup, it passes without the :order option, indicating that there is a problem with the join based mechanism.

Thanks

So is this a valid Rails bug ? Should I create a ticket for it on Lighthouse ?

So is this a valid Rails bug ? Should I create a ticket for it on Lighthouse
?

Seems like you already have :-). I'd definitely check against 2.3.2 -
I remember there being a fix for a :include bug somewhere.

Fred

Just checked, this test fails on Rails 2.3.2 too.

Thanks for looking into it.

The ticket is at https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/2341-nested-finder-include-option-with-has_one#ticket-2341-4

Not sure how the ticket assignment thing works :wink:

Thanks