From 2001a00d2c56aaacafd082192910507582cc6ca4 Mon Sep 17 00:00:00 2001 From: Frederick Cheung Date: Fri, 2 May 2008 00:00:42 +0100 Subject: [PATCH] Ensure correct record is returned when preloading has_one where more than one row exists --- .../lib/active_record/association_preload.rb | 7 ++++++- activerecord/test/cases/associations/eager_test.rb | 4 ++++ activerecord/test/models/post.rb | 2 ++ 3 files changed, 12 insertions(+), 1 deletions(-) diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index 3e7c787..da4ebde 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -65,7 +65,13 @@ module ActiveRecord end def set_association_single_records(id_to_record_map, reflection_name, associated_records, key) + seen_keys = {} associated_records.each do |associated_record| + #this is a has_one or belongs_to: there should only be one record. + #Unfortunately we can't (in portable way) ask the database for 'all records where foo_id in (x,y,z), but please + # only one row per distinct foo_id' so this where we enforce that + next if seen_keys[associated_record[key].to_s] + seen_keys[associated_record[key].to_s] = true mapped_records = id_to_record_map[associated_record[key].to_s] mapped_records.each do |mapped_record| mapped_record.send("set_#{reflection_name}_target", associated_record) @@ -122,7 +128,6 @@ module ActiveRecord else records.each {|record| record.send("set_#{reflection.name}_target", nil)} - set_association_single_records(id_to_record_map, reflection.name, find_associated_records(ids, reflection, preload_options), reflection.primary_key_name) end end diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb index 546ed80..10bd57c 100644 --- a/activerecord/test/cases/associations/eager_test.rb +++ b/activerecord/test/cases/associations/eager_test.rb @@ -29,6 +29,10 @@ class EagerAssociationTest < ActiveRecord::TestCase post = Post.find(:first, :include => :comments, :conditions => "posts.title = 'Welcome to the weblog'") assert_equal 2, post.comments.size assert post.comments.include?(comments(:greetings)) + + posts = Post.find(:all, :include => :last_comment) + post = posts.find { |p| p.id == 1 } + assert_equal Post.find(1).last_comment, post.last_comment end def test_loading_conditions_with_or diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb index 22c5a64..f2d45d9 100644 --- a/activerecord/test/models/post.rb +++ b/activerecord/test/models/post.rb @@ -9,6 +9,8 @@ class Post < ActiveRecord::Base belongs_to :author_with_posts, :class_name => "Author", :foreign_key => :author_id, :include => :posts + has_one :last_comment, :class_name => 'Comment', :order => 'id desc' + has_many :comments, :order => "body" do def find_most_recent find(:first, :order => "id DESC") -- 1.5.4.4