From ec0928076529e8f0b5a4ad58c95cfa1fe6ed5b60 Mon Sep 17 00:00:00 2001 From: Ivan Antropov Date: Sun, 10 Nov 2013 12:28:54 +0700 Subject: Fix insertion of records for hmt association with scope, fix #3548 --- activerecord/CHANGELOG.md | 6 ++++++ .../associations/has_many_through_association.rb | 6 +++++- activerecord/lib/active_record/relation.rb | 4 ++-- .../associations/has_many_through_associations_test.rb | 14 +++++++++++++- activerecord/test/cases/relation_test.rb | 4 ++++ activerecord/test/models/club.rb | 2 ++ 6 files changed, 32 insertions(+), 4 deletions(-) diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 0bef057836..89fcc129ca 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,9 @@ +* Fix insertion of records via has_many_through association with scope + + Fixes #3548 + + *Ivan Antropov* + * Checks to see if the record contains the foreign key to set the inverse automatically. *Edo Balvers* diff --git a/activerecord/lib/active_record/associations/has_many_through_association.rb b/activerecord/lib/active_record/associations/has_many_through_association.rb index 31b8d27892..53268372eb 100644 --- a/activerecord/lib/active_record/associations/has_many_through_association.rb +++ b/activerecord/lib/active_record/associations/has_many_through_association.rb @@ -84,12 +84,16 @@ module ActiveRecord @through_records[record.object_id] ||= begin ensure_mutable - through_record = through_association.build + through_record = through_association.build through_scope_attributes through_record.send("#{source_reflection.name}=", record) through_record end end + def through_scope_attributes + scope.where_values_hash(through_association.reflection.name.to_s) + end + def save_through_record(record) build_through_record(record).save! ensure diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index 6e0669a77f..5e38ed632d 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -527,9 +527,9 @@ module ActiveRecord # # User.where(name: 'Oscar').where_values_hash # # => {name: "Oscar"} - def where_values_hash + def where_values_hash(relation_table_name = table_name) equalities = where_values.grep(Arel::Nodes::Equality).find_all { |node| - node.left.relation.name == table_name + node.left.relation.name == relation_table_name } binds = Hash[bind_values.find_all(&:first).map { |column, v| [column.name, v] }] 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 47592f312e..8017ed169c 100644 --- a/activerecord/test/cases/associations/has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb @@ -1095,7 +1095,19 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase assert_equal [posts(:thinking)], person.reload.first_posts end - def test_has_many_through_with_includes_in_through_association_scope + test "has many through with includes in through association scope" do assert_not_empty posts(:welcome).author_address_extra_with_address end + + test "insert records via has_many_through association with scope" do + club = Club.create! + member = Member.create! + Membership.create!(club: club, member: member) + + club.favourites << member + assert_equal [member], club.favourites + + club.reload + assert_equal [member], club.favourites + end end diff --git a/activerecord/test/cases/relation_test.rb b/activerecord/test/cases/relation_test.rb index 70d113fb39..e83aafc842 100644 --- a/activerecord/test/cases/relation_test.rb +++ b/activerecord/test/cases/relation_test.rb @@ -16,6 +16,10 @@ module ActiveRecord def self.connection Post.connection end + + def self.table_name + 'fake_table' + end end def test_construction diff --git a/activerecord/test/models/club.rb b/activerecord/test/models/club.rb index 566e0873f1..902a047f62 100644 --- a/activerecord/test/models/club.rb +++ b/activerecord/test/models/club.rb @@ -6,6 +6,8 @@ class Club < ActiveRecord::Base has_one :sponsored_member, :through => :sponsor, :source => :sponsorable, :source_type => "Member" belongs_to :category + has_many :favourites, -> { where(memberships: { favourite: true}) }, through: :memberships, source: :member + private def private_method -- cgit v1.2.3