From 1813350f0927dde01a11ebbd33a8f6b0deacd073 Mon Sep 17 00:00:00 2001 From: Zoltan Kiss Date: Fri, 10 Oct 2014 15:13:53 -0500 Subject: Fix nested `has many :through` associations on unpersisted instances Fixes: #16313 --- .../associations/through_association.rb | 2 +- activerecord/lib/active_record/reflection.rb | 4 +++ .../has_many_through_associations_test.rb | 29 ++++++++++++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/associations/through_association.rb b/activerecord/lib/active_record/associations/through_association.rb index af1bce523c..a276907dd3 100644 --- a/activerecord/lib/active_record/associations/through_association.rb +++ b/activerecord/lib/active_record/associations/through_association.rb @@ -77,7 +77,7 @@ module ActiveRecord end def foreign_key_present? - through_reflection.belongs_to? && !owner[through_reflection.foreign_key].nil? + through_reflection.belongs_to_or_through? && !owner[through_reflection.foreign_key].nil? end def ensure_mutable diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 4265afc0a5..09d61b47a2 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -139,6 +139,10 @@ module ActiveRecord klass.type_for_attribute(klass.primary_key) end + def belongs_to_or_through? + belongs_to? || (through_reflection && through_reflection.belongs_to_or_through?) + end + # Returns the class name for the macro. # # composed_of :balance, class_name: 'Money' returns 'Money' 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 5f52c65412..83365884f5 100644 --- a/activerecord/test/cases/associations/has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb @@ -1166,4 +1166,33 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase post_through = organization.posts.build assert_equal post_direct.author_id, post_through.author_id end + + def test_single_has_many_through_association_with_unpersisted_parent_instance + post_with_single_has_many_through = Class.new(Post) do + def self.name; 'PostWithSingleHasManyThrough'; end + has_many :subscriptions, through: :author + end + post = post_with_single_has_many_through.new + post.author = Author.create!(name: 'Federico Morissette') + book = Book.create!(name: 'essays on single has many through associations') + post.author.books << book + subscription = Subscription.first + book.subscriptions << subscription + assert_equal [subscription], post.subscriptions.to_a + end + + def test_nested_has_many_through_association_with_unpersisted_parent_instance + post_with_nested_has_many_through = Class.new(Post) do + def self.name; 'PostWithNestedHasManyThrough'; end + has_many :books, through: :author + has_many :subscriptions, through: :books + end + post = post_with_nested_has_many_through.new + post.author = Author.create!(name: 'Obie Weissnat') + book = Book.create!(name: 'essays on nested single has many through associations') + post.author.books << book + subscription = Subscription.first + book.subscriptions << subscription + assert_equal [subscription], post.subscriptions.to_a + end end -- cgit v1.2.3