diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 10ecd068d3..419967b833 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1273,9 +1273,16 @@ module ActiveRecord if send(reflection.name).loaded? || reflection.options[:finder_sql] send(reflection.name).map(&:id) else - send(reflection.name).all(:select => "#{reflection.quoted_table_name}.#{reflection.klass.primary_key}").map(&:id) + if reflection.through_reflection && reflection.source_reflection.belongs_to? + through = reflection.through_reflection + primary_key = reflection.source_reflection.primary_key_name + send(through.name).all(:select => "DISTINCT #{through.quoted_table_name}.#{primary_key}").map!(&:"#{primary_key}") + else + send(reflection.name).all(:select => "#{reflection.quoted_table_name}.#{reflection.klass.primary_key}").map!(&:id) + end end end + end def collection_accessor_methods(reflection, association_proxy_class, writer = true) diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb index 7a4712d7c8..8529ff0285 100644 --- a/activerecord/test/cases/associations/has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb @@ -243,8 +243,12 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase assert_equal 2, people(:michael).jobs.size end - def test_get_ids - assert_equal [posts(:welcome).id, posts(:authorless).id].sort, people(:michael).post_ids.sort + def test_get_ids_for_belongs_to_source + assert_sql(/DISTINCT/) { assert_equal [posts(:welcome).id, posts(:authorless).id].sort, people(:michael).post_ids.sort } + end + + def test_get_ids_for_has_many_source + assert_equal [comments(:eager_other_comment1).id], authors(:mary).comment_ids end def test_get_ids_for_loaded_associations diff --git a/activesupport/lib/active_support/core_ext/hash/deep_merge.rb b/activesupport/lib/active_support/core_ext/hash/deep_merge.rb index b009be3d84..ffde34a741 100644 --- a/activesupport/lib/active_support/core_ext/hash/deep_merge.rb +++ b/activesupport/lib/active_support/core_ext/hash/deep_merge.rb @@ -4,7 +4,7 @@ class Hash merge(other_hash) do |key, oldval, newval| oldval = oldval.to_hash if oldval.respond_to?(:to_hash) newval = newval.to_hash if newval.respond_to?(:to_hash) - oldval.class.to_s == 'Hash' && newval.class.to_s == 'Hash' ? oldval.deep_merge(newval) : newval + oldval.is_a?( Hash ) && newval.is_a?( Hash ) ? oldval.deep_merge(newval) : newval end end diff --git a/activesupport/lib/active_support/core_ext/hash/diff.rb b/activesupport/lib/active_support/core_ext/hash/diff.rb index da98593458..b904f49fa8 100644 --- a/activesupport/lib/active_support/core_ext/hash/diff.rb +++ b/activesupport/lib/active_support/core_ext/hash/diff.rb @@ -8,6 +8,6 @@ class Hash # {}.diff(1 => 2) # => {1 => 2} # {1 => 2, 3 => 4}.diff(1 => 2) # => {3 => 4} def diff(h2) - dup.delete_if { |k, v| h2[k] == v }.merge(h2.dup.delete_if { |k, v| has_key?(k) }) + dup.delete_if { |k, v| h2[k] == v }.merge!(h2.dup.delete_if { |k, v| has_key?(k) }) end end diff --git a/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb b/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb index ebfdcb2cf0..d7ebd5feef 100644 --- a/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb +++ b/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb @@ -21,7 +21,7 @@ class Hash # Performs the opposite of merge, with the keys and values from the first hash taking precedence over the second. # Modifies the receiver in place. def reverse_merge!(other_hash) - replace(reverse_merge(other_hash)) + merge!( other_hash ){|k,o,n| o } end alias_method :reverse_update, :reverse_merge! diff --git a/activesupport/lib/active_support/hash_with_indifferent_access.rb b/activesupport/lib/active_support/hash_with_indifferent_access.rb index 61fc6475a0..543dab4a75 100644 --- a/activesupport/lib/active_support/hash_with_indifferent_access.rb +++ b/activesupport/lib/active_support/hash_with_indifferent_access.rb @@ -98,6 +98,10 @@ module ActiveSupport super other_hash.with_indifferent_access end + def reverse_merge!(other_hash) + replace(reverse_merge( other_hash )) + end + # Removes a specified key from the hash. def delete(key) super(convert_key(key)) @@ -109,7 +113,7 @@ module ActiveSupport # Convert to a Hash with String keys. def to_hash - Hash.new(default).merge(self) + Hash.new(default).merge!(self) end protected