Skip to content
This repository
Browse code

Stop assuming strings for grouped calculations

Execute_grouped_calculation is one of those places where
ActiveRecord forgets that it has ARel underpinnings, and
assumes that the values provided to group_values are
strings. This artificially hobbles otherwise functional
code. This patch stops assuming that incoming values
respond to to_sym, stops using string interpolation for
table aliases on objects that support aliasing, and stops
unnecessarily joining group_values on the relation.

Additionally, it calls to_sql, if available, on objects
sent to column_alias_for, in order to get a more reasonable
alias string than a non-string's default to_str method.
  • Loading branch information...
commit a1c05dd8b9bd3623289d3aa73dda2943d620cc34 1 parent ebe8a45
Ernie Miller authored June 24, 2012
23  activerecord/lib/active_record/relation/calculations.rb
@@ -262,10 +262,16 @@ def execute_simple_calculation(operation, column_name, distinct) #:nodoc:
262 262
     end
263 263
 
264 264
     def execute_grouped_calculation(operation, column_name, distinct) #:nodoc:
265  
-      group_attr      = group_values
266  
-      association     = @klass.reflect_on_association(group_attr.first.to_sym)
267  
-      associated      = group_attr.size == 1 && association && association.macro == :belongs_to # only count belongs_to associations
268  
-      group_fields  = Array(associated ? association.foreign_key : group_attr)
  265
+      group_attrs = group_values
  266
+
  267
+      if group_attrs.first.respond_to?(:to_sym)
  268
+        association = @klass.reflect_on_association(group_attrs.first.to_sym)
  269
+        associated  = group_attrs.size == 1 && association && association.macro == :belongs_to # only count belongs_to associations
  270
+        group_fields  = Array(associated ? association.foreign_key : group_attrs)
  271
+      else
  272
+        group_fields = group_attrs
  273
+      end
  274
+
269 275
       group_aliases = group_fields.map { |field| column_alias_for(field) }
270 276
       group_columns = group_aliases.zip(group_fields).map { |aliaz,field|
271 277
         [aliaz, column_for(field)]
@@ -288,10 +294,14 @@ def execute_grouped_calculation(operation, column_name, distinct) #:nodoc:
288 294
       select_values += select_values unless having_values.empty?
289 295
 
290 296
       select_values.concat group_fields.zip(group_aliases).map { |field,aliaz|
291  
-        "#{field} AS #{aliaz}"
  297
+        if field.respond_to?(:as)
  298
+          field.as(aliaz)
  299
+        else
  300
+          "#{field} AS #{aliaz}"
  301
+        end
292 302
       }
293 303
 
294  
-      relation = except(:group).group(group.join(','))
  304
+      relation = except(:group).group(group)
295 305
       relation.select_values = select_values
296 306
 
297 307
       calculated_data = @klass.connection.select_all(relation, nil, bind_values)
@@ -321,6 +331,7 @@ def execute_grouped_calculation(operation, column_name, distinct) #:nodoc:
321 331
     #   column_alias_for("count(*)")                 # => "count_all"
322 332
     #   column_alias_for("count", "id")              # => "count_id"
323 333
     def column_alias_for(*keys)
  334
+      keys.map! {|k| k.respond_to?(:to_sql) ? k.to_sql : k}
324 335
       table_name = keys.join(' ')
325 336
       table_name.downcase!
326 337
       table_name.gsub!(/\*/, 'all')
5  activerecord/test/cases/calculations_test.rb
@@ -61,6 +61,11 @@ def test_should_group_by_field
61 61
     [1,6,2].each { |firm_id| assert c.keys.include?(firm_id) }
62 62
   end
63 63
 
  64
+  def test_should_group_by_arel_attribute
  65
+    c = Account.sum(:credit_limit, :group => Account.arel_table[:firm_id])
  66
+    [1,6,2].each { |firm_id| assert c.keys.include?(firm_id) }
  67
+  end
  68
+
64 69
   def test_should_group_by_multiple_fields
65 70
     c = Account.group('firm_id', :credit_limit).count(:all)
66 71
     [ [nil, 50], [1, 50], [6, 50], [6, 55], [9, 53], [2, 60] ].each { |firm_and_limit| assert c.keys.include?(firm_and_limit) }

0 notes on commit a1c05dd

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