From 48ec2628aca48a82a8dd6c083c4d676f1cd4a2e9 Mon Sep 17 00:00:00 2001 From: Henry Hsu Date: Sun, 18 Jul 2010 10:05:54 -0700 Subject: [PATCH] Fix a bug where eager loading of a :uniq => true has_and_belongs_to_many returns duplicate entries --- .../lib/active_record/association_preload.rb | 3 ++- .../has_and_belongs_to_many_associations_test.rb | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 1 deletions(-) diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index cbec578..a2a3772 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -191,11 +191,12 @@ module ActiveRecord conditions = "t0.#{reflection.primary_key_name} #{in_or_equals_for_ids(ids)}" conditions << append_conditions(reflection, preload_options) + distinct = "DISTINCT " if options[:uniq] associated_records = reflection.klass.unscoped.where([conditions, ids]). includes(options[:include]). joins("INNER JOIN #{connection.quote_table_name options[:join_table]} t0 ON #{reflection.klass.quoted_table_name}.#{reflection.klass.primary_key} = t0.#{reflection.association_foreign_key}"). - select("#{options[:select] || table_name+'.*'}, t0.#{reflection.primary_key_name} as the_parent_record_id"). + select("#{options[:select] || "#{distinct}#{table_name}.*"}, t0.#{reflection.primary_key_name} as the_parent_record_id"). order(options[:order]).to_a set_association_collection_records(id_to_record_map, reflection.name, associated_records, 'the_parent_record_id') diff --git a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb index b11969a..bb46dff 100644 --- a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb @@ -323,6 +323,21 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase assert_equal 3, project.developers.size end + def test_uniq_option_with_eager_loading + project = projects(:active_record) + project_id = project.id + dev_3 = developers(:dev_3) + + assert_equal 3, project.developers.size + 5.times do + project.developers << dev_3 + end + assert_equal 4, project.developers.size + + project = Project.find(project.id, :include => [:developers]) + assert_equal 4, project.developers.size + end + def test_deleting david = Developer.find(1) active_record = Project.find(1) -- 1.7.1