From 56b870f243c1a73a1d15638500e5aa5e7ae9a1cc Mon Sep 17 00:00:00 2001
From: Ryuta Kamizono <kamipo@gmail.com>
Date: Tue, 15 Aug 2017 21:39:40 +0900
Subject: Through scope should not be affected by scoping

Follow up of #29834.

Fixes #30266.
---
 .../associations/preloader/association.rb             | 12 +-----------
 .../active_record/associations/through_association.rb |  2 +-
 activerecord/lib/active_record/reflection.rb          |  9 ++-------
 activerecord/lib/active_record/scoping/named.rb       | 10 ++++++++++
 .../has_many_through_associations_test.rb             | 19 +++++++++++++++++++
 5 files changed, 33 insertions(+), 19 deletions(-)

(limited to 'activerecord')

diff --git a/activerecord/lib/active_record/associations/preloader/association.rb b/activerecord/lib/active_record/associations/preloader/association.rb
index 5ba03c555a..4915a37f06 100644
--- a/activerecord/lib/active_record/associations/preloader/association.rb
+++ b/activerecord/lib/active_record/associations/preloader/association.rb
@@ -116,18 +116,8 @@ module ActiveRecord
             @reflection_scope ||= reflection.scope_for(klass)
           end
 
-          def klass_scope
-            current_scope = klass.current_scope
-
-            if current_scope && current_scope.empty_scope?
-              klass.unscoped
-            else
-              klass.default_scoped
-            end
-          end
-
           def build_scope
-            scope = klass_scope
+            scope = klass.scope_for_association
 
             if reflection.type
               scope.where!(reflection.type => model.base_class.sti_name)
diff --git a/activerecord/lib/active_record/associations/through_association.rb b/activerecord/lib/active_record/associations/through_association.rb
index 76237c4a0c..cba565448f 100644
--- a/activerecord/lib/active_record/associations/through_association.rb
+++ b/activerecord/lib/active_record/associations/through_association.rb
@@ -15,7 +15,7 @@ module ActiveRecord
         def target_scope
           scope = super
           reflection.chain.drop(1).each do |reflection|
-            relation = reflection.klass.all
+            relation = reflection.klass.scope_for_association
             scope.merge!(
               relation.except(:select, :create_with, :includes, :preload, :joins, :eager_load)
             )
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb
index b2c62cd686..b847933b2e 100644
--- a/activerecord/lib/active_record/reflection.rb
+++ b/activerecord/lib/active_record/reflection.rb
@@ -221,13 +221,8 @@ module ActiveRecord
       end
 
       def klass_join_scope(table, predicate_builder) # :nodoc:
-        current_scope = klass.current_scope
-
-        if current_scope && current_scope.empty_scope?
-          build_scope(table, predicate_builder)
-        else
-          klass.default_scoped(build_scope(table, predicate_builder))
-        end
+        relation = build_scope(table, predicate_builder)
+        klass.scope_for_association(relation)
       end
 
       def constraints
diff --git a/activerecord/lib/active_record/scoping/named.rb b/activerecord/lib/active_record/scoping/named.rb
index 43cce19c1f..6fa096c1fe 100644
--- a/activerecord/lib/active_record/scoping/named.rb
+++ b/activerecord/lib/active_record/scoping/named.rb
@@ -31,6 +31,16 @@ module ActiveRecord
           end
         end
 
+        def scope_for_association(scope = relation) # :nodoc:
+          current_scope = self.current_scope
+
+          if current_scope && current_scope.empty_scope?
+            scope
+          else
+            default_scoped(scope)
+          end
+        end
+
         def default_scoped(scope = relation) # :nodoc:
           build_default_scope(scope) || scope
         end
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 968c0eb944..f8ea51225a 100644
--- a/activerecord/test/cases/associations/has_many_through_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb
@@ -1261,6 +1261,25 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
     assert_equal 0, users[2].family_members.to_a.size
   end
 
+  def test_through_scope_is_affected_by_unscoping
+    author = authors(:david)
+
+    expected = author.comments.to_a
+    FirstPost.unscoped do
+      assert_equal expected.sort_by(&:id), author.comments_on_first_posts.sort_by(&:id)
+    end
+  end
+
+  def test_through_scope_isnt_affected_by_scoping
+    author = authors(:david)
+
+    expected = author.comments_on_first_posts.to_a
+    FirstPost.where(id: 2).scoping do
+      author.comments_on_first_posts.reset
+      assert_equal expected.sort_by(&:id), author.comments_on_first_posts.sort_by(&:id)
+    end
+  end
+
   def test_incorrectly_ordered_through_associations
     assert_raises(ActiveRecord::HasManyThroughOrderError) do
       DeveloperWithIncorrectlyOrderedHasManyThrough.create(
-- 
cgit v1.2.3