public
Description: Ruby on Rails
Homepage: http://rubyonrails.org
Clone URL: git://github.com/rails/rails.git
Ensure :include checks joins when determining if it can preload [#528 
state:resolved]
fcheung (author)
Thu Dec 18 11:07:55 -0800 2008
lifo (committer)
Thu Dec 18 11:19:36 -0800 2008
commit  c9ab7098be7bdd748c0f4a49c8ef015b4aad3108
tree    aedc907d37039a5cbf8dca55f6f7a6f84a37c0c3
parent  9cf6b1b15e6335134a5af5d9d6296f8d9242e005
...
1731
1732
1733
 
 
 
 
 
1734
1735
1736
...
1741
1742
1743
1744
 
1745
1746
1747
1748
1749
1750
 
1751
1752
1753
1754
1755
1756
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1757
1758
1759
1760
1761
 
 
1762
1763
1764
1765
1766
 
 
1767
1768
1769
1770
 
 
1771
1772
1773
1774
 
 
1775
1776
1777
...
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
...
1746
1747
1748
 
1749
1750
1751
1752
1753
1754
 
1755
1756
1757
1758
1759
1760
 
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
 
 
1782
1783
1784
1785
1786
 
 
1787
1788
1789
1790
 
 
1791
1792
1793
1794
1795
 
1796
1797
1798
1799
1800
0
@@ -1731,6 +1731,11 @@ module ActiveRecord
0
           return sanitize_sql(sql)
0
         end
0
 
0
+        def tables_in_string(string)
0
+          return [] if string.blank?
0
+          string.scan(/([\.a-zA-Z_]+).?\./).flatten
0
+        end
0
+
0
         def conditions_tables(options)
0
           # look in both sets of conditions
0
           conditions = [scope(:find, :conditions), options[:conditions]].inject([]) do |all, cond|
0
@@ -1741,37 +1746,55 @@ module ActiveRecord
0
               else            all << cond
0
             end
0
           end
0
-          conditions.join(' ').scan(/([\.a-zA-Z_]+).?\./).flatten
0
+          tables_in_string(conditions.join(' '))
0
         end
0
 
0
         def order_tables(options)
0
           order = [options[:order], scope(:find, :order) ].join(", ")
0
           return [] unless order && order.is_a?(String)
0
-          order.scan(/([\.a-zA-Z_]+).?\./).flatten
0
+          tables_in_string(order)
0
         end
0
 
0
         def selects_tables(options)
0
           select = options[:select]
0
           return [] unless select && select.is_a?(String)
0
-          select.scan(/"?([\.a-zA-Z_]+)"?.?\./).flatten
0
+          tables_in_string(select)
0
+        end
0
+
0
+        def joined_tables(options)
0
+          scope = scope(:find)
0
+          joins = options[:joins]
0
+          merged_joins = scope && scope[:joins] && joins ? merge_joins(scope[:joins], joins) : (joins || scope && scope[:joins])
0
+          [table_name] + case merged_joins
0
+          when Symbol, Hash, Array
0
+            if array_of_strings?(merged_joins)
0
+              tables_in_string(merged_joins.join(' '))
0
+            else
0
+              join_dependency = ActiveRecord::Associations::ClassMethods::InnerJoinDependency.new(self, merged_joins, nil)
0
+              [table_name] + join_dependency.join_associations.collect {|join_association| [join_association.aliased_join_table_name, join_association.aliased_table_name]}.flatten.compact
0
+            end
0
+          else
0
+            tables_in_string(merged_joins)
0
+          end
0
         end
0
 
0
         # Checks if the conditions reference a table other than the current model table
0
-        def include_eager_conditions?(options, tables = nil)
0
-          ((tables || conditions_tables(options)) - [table_name]).any?
0
+        def include_eager_conditions?(options, tables = nil, joined_tables = nil)
0
+          ((tables || conditions_tables(options)) - (joined_tables || joined_tables(options))).any?
0
         end
0
 
0
         # Checks if the query order references a table other than the current model's table.
0
-        def include_eager_order?(options, tables = nil)
0
-          ((tables || order_tables(options)) - [table_name]).any?
0
+        def include_eager_order?(options, tables = nil, joined_tables = nil)
0
+          ((tables || order_tables(options)) - (joined_tables || joined_tables(options))).any?
0
         end
0
 
0
-        def include_eager_select?(options)
0
-          (selects_tables(options) - [table_name]).any?
0
+        def include_eager_select?(options, joined_tables = nil)
0
+          (selects_tables(options) - (joined_tables || joined_tables(options))).any?
0
         end
0
 
0
         def references_eager_loaded_tables?(options)
0
-          include_eager_order?(options) || include_eager_conditions?(options) || include_eager_select?(options)
0
+          joined_tables = joined_tables(options)
0
+          include_eager_order?(options, nil, joined_tables) || include_eager_conditions?(options, nil, joined_tables) || include_eager_select?(options, joined_tables)
0
         end
0
 
0
         def using_limitable_reflections?(reflections)
...
1
2
3
 
4
5
6
...
706
707
708
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
709
...
1
2
3
4
5
6
7
...
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
0
@@ -1,6 +1,7 @@
0
 require "cases/helper"
0
 require 'models/post'
0
 require 'models/tagging'
0
+require 'models/tag'
0
 require 'models/comment'
0
 require 'models/author'
0
 require 'models/category'
0
@@ -706,4 +707,68 @@ class EagerAssociationTest < ActiveRecord::TestCase
0
     assert_equal 5, Developer.find(:all, :include => 'projects', :order => 'developers_projects.joined_on DESC', :limit => 5).size
0
   end
0
 
0
+  def test_eager_loading_with_order_on_joined_table_preloads
0
+    posts = assert_queries(2) do
0
+      Post.find(:all, :joins => :comments, :include => :author, :order => 'comments.id DESC')
0
+    end
0
+    assert_equal posts(:eager_other), posts[0]
0
+    assert_equal authors(:mary), assert_no_queries { posts[0].author}
0
+  end
0
+
0
+  def test_eager_loading_with_conditions_on_joined_table_preloads
0
+    posts = assert_queries(2) do
0
+      Post.find(:all, :select => 'distinct posts.*', :include => :author, :joins => [:comments], :conditions => "comments.body like 'Thank you%'", :order => 'posts.id')
0
+    end
0
+    assert_equal [posts(:welcome)], posts
0
+    assert_equal authors(:david), assert_no_queries { posts[0].author}
0
+
0
+    posts = assert_queries(2) do
0
+      Post.find(:all, :select => 'distinct posts.*', :include => :author, :joins => [:comments], :conditions => "comments.body like 'Thank you%'", :order => 'posts.id')
0
+    end
0
+    assert_equal [posts(:welcome)], posts
0
+    assert_equal authors(:david), assert_no_queries { posts[0].author}
0
+
0
+    posts = assert_queries(2) do
0
+      Post.find(:all, :include => :author, :joins => {:taggings => :tag}, :conditions => "tags.name = 'General'")
0
+    end
0
+    assert_equal posts(:welcome, :thinking), posts
0
+
0
+    posts = assert_queries(2) do
0
+      Post.find(:all, :include => :author, :joins => {:taggings => {:tag => :taggings}}, :conditions => "taggings_tags.super_tag_id=2")
0
+    end
0
+    assert_equal posts(:welcome, :thinking), posts
0
+
0
+  end
0
+
0
+  def test_eager_loading_with_conditions_on_string_joined_table_preloads
0
+    posts = assert_queries(2) do
0
+      Post.find(:all, :select => 'distinct posts.*', :include => :author, :joins => "INNER JOIN comments on comments.post_id = posts.id", :conditions => "comments.body like 'Thank you%'", :order => 'posts.id')
0
+    end
0
+    assert_equal [posts(:welcome)], posts
0
+    assert_equal authors(:david), assert_no_queries { posts[0].author}
0
+
0
+    posts = assert_queries(2) do
0
+      Post.find(:all, :select => 'distinct posts.*', :include => :author, :joins => ["INNER JOIN comments on comments.post_id = posts.id"], :conditions => "comments.body like 'Thank you%'", :order => 'posts.id')
0
+    end
0
+    assert_equal [posts(:welcome)], posts
0
+    assert_equal authors(:david), assert_no_queries { posts[0].author}
0
+
0
+  end
0
+
0
+  def test_eager_loading_with_select_on_joined_table_preloads
0
+    posts = assert_queries(2) do
0
+      Post.find(:all, :select => 'posts.*, authors.name as author_name', :include => :comments, :joins => :author, :order => 'posts.id')
0
+    end
0
+    assert_equal 'David', posts[0].author_name
0
+    assert_equal posts(:welcome).comments, assert_no_queries { posts[0].comments}
0
+  end
0
+
0
+  def test_eager_loading_with_conditions_on_join_model_preloads
0
+    authors = assert_queries(2) do
0
+      Author.find(:all, :include => :author_address, :joins => :comments, :conditions => "posts.title like 'Welcome%'")
0
+    end
0
+    assert_equal authors(:david), authors[0]
0
+    assert_equal author_addresses(:david_address), authors[0].author_address
0
+  end
0
+
0
 end

Comments