Skip to content
This repository
Browse code

Add Relation#construct_relation_for_association_calculations for calc…

…ulations with includes
  • Loading branch information...
commit b9599502c9e738a5a1513e75d08f8d40ed408265 1 parent 71d67fc
Pratik authored January 19, 2010
25  activerecord/lib/active_record/calculations.rb
@@ -2,8 +2,6 @@ module ActiveRecord
2 2
   module Calculations #:nodoc:
3 3
     extend ActiveSupport::Concern
4 4
 
5  
-    CALCULATIONS_OPTIONS = [:conditions, :joins, :order, :select, :group, :having, :distinct, :limit, :offset, :include, :from]
6  
-
7 5
     module ClassMethods
8 6
       # Count operates using three different approaches.
9 7
       #
@@ -147,26 +145,11 @@ def calculate(operation, column_name, options = {})
147 145
       end
148 146
 
149 147
       private
150  
-        def validate_calculation_options(options = {})
151  
-          options.assert_valid_keys(CALCULATIONS_OPTIONS)
152  
-        end
153  
-
154  
-        def construct_calculation_arel(options = {})
155  
-          validate_calculation_options(options)
156  
-          options = options.except(:distinct)
157  
-
158  
-          merge_with_includes = current_scoped_methods ? current_scoped_methods.includes_values : []
159  
-          includes = (merge_with_includes + Array.wrap(options[:include])).uniq
160 148
 
161  
-          if includes.any?
162  
-            merge_with_joins = current_scoped_methods ? current_scoped_methods.joins_values : []
163  
-            joins = (merge_with_joins + Array.wrap(options[:joins])).uniq
164  
-            join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(self, includes, construct_join(joins))
165  
-            construct_finder_arel_with_included_associations(options, join_dependency)
166  
-          else
167  
-            scoped.apply_finder_options(options)
168  
-          end
169  
-        end
  149
+      def construct_calculation_arel(options = {})
  150
+        relation = scoped.apply_finder_options(options.except(:distinct))
  151
+        (relation.eager_loading? || relation.includes_values.present?) ? relation.send(:construct_relation_for_association_calculations) : relation
  152
+      end
170 153
 
171 154
     end
172 155
   end
11  activerecord/lib/active_record/relation.rb
@@ -45,12 +45,10 @@ def respond_to?(method, include_private = false)
45 45
     def to_a
46 46
       return @records if loaded?
47 47
 
48  
-      eager_loading = @eager_load_values.any? || (@includes_values.any? && references_eager_loaded_tables?)
49  
-
50  
-      @records = eager_loading ? find_with_associations : @klass.find_by_sql(arel.to_sql)
  48
+      @records = eager_loading? ? find_with_associations : @klass.find_by_sql(arel.to_sql)
51 49
 
52 50
       preload = @preload_values
53  
-      preload +=  @includes_values unless eager_loading
  51
+      preload +=  @includes_values unless eager_loading?
54 52
       preload.each {|associations| @klass.send(:preload_associations, @records, associations) } 
55 53
 
56 54
       # @readonly_value is true only if set explicity. @implicit_readonly is true if there are JOINS and no explicit SELECT.
@@ -112,6 +110,7 @@ def reload
112 110
 
113 111
     def reset
114 112
       @first = @last = @to_sql = @order_clause = @scope_for_create = @arel = @loaded = nil
  113
+      @should_eager_load = @join_dependency = nil
115 114
       @records = []
116 115
       self
117 116
     end
@@ -133,6 +132,10 @@ def scope_for_create
133 132
       end
134 133
     end
135 134
 
  135
+    def eager_loading?
  136
+      @should_eager_load ||= (@eager_load_values.any? || (@includes_values.any? && references_eager_loaded_tables?))
  137
+    end
  138
+
136 139
     protected
137 140
 
138 141
     def method_missing(method, *args, &block)
6  activerecord/lib/active_record/relation/finder_methods.rb
@@ -53,6 +53,12 @@ def find_with_associations
53 53
       []
54 54
     end
55 55
 
  56
+    def construct_relation_for_association_calculations
  57
+      including = (@eager_load_values + @includes_values).uniq
  58
+      join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(@klass, including, arel.joins(arel))
  59
+      construct_relation_for_association_find(join_dependency)
  60
+    end
  61
+
56 62
     def construct_relation_for_association_find(join_dependency)
57 63
       relation = except(:includes, :eager_load, :preload, :select).select(@klass.send(:column_aliases, join_dependency))
58 64
 
17  activerecord/test/cases/calculations_test.rb
@@ -246,23 +246,6 @@ def test_should_group_by_summed_field_through_association_and_having
246 246
     assert_equal 8, c['Jadedpixel']
247 247
   end
248 248
 
249  
-  def test_should_reject_invalid_options
250  
-    assert_nothing_raised do
251  
-      # empty options are valid
252  
-      Company.send(:validate_calculation_options)
253  
-      # these options are valid for all calculations
254  
-      [:select, :conditions, :joins, :order, :group, :having, :distinct].each do |opt|
255  
-        Company.send(:validate_calculation_options, opt => true)
256  
-      end
257  
-
258  
-      # :include is only valid on :count
259  
-      Company.send(:validate_calculation_options, :include => true)
260  
-    end
261  
-
262  
-    assert_raise(ArgumentError) { Company.send(:validate_calculation_options, :sum,   :foo => :bar) }
263  
-    assert_raise(ArgumentError) { Company.send(:validate_calculation_options, :count, :foo => :bar) }
264  
-  end
265  
-
266 249
   def test_should_count_selected_field_with_include
267 250
     assert_equal 6, Account.count(:distinct => true, :include => :firm)
268 251
     assert_equal 4, Account.count(:distinct => true, :include => :firm, :select => :credit_limit)

0 notes on commit b959950

Please sign in to comment.
Something went wrong with that request. Please try again.