Skip to content

Commit 5147c48

Browse files
committed
Fix sum with qualified name on loaded relation
Since rails#53064, calling `sum` on a loaded relation raised `ActiveRecord::UnmodifiableRelation`.
1 parent 6a47039 commit 5147c48

File tree

2 files changed

+29
-15
lines changed

2 files changed

+29
-15
lines changed

activerecord/lib/active_record/relation/calculations.rb

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,18 @@ def async_ids
410410
async.ids
411411
end
412412

413+
protected
414+
def aggregate_column(column_name)
415+
case column_name
416+
when Arel::Expressions
417+
column_name
418+
when :all
419+
Arel.star
420+
else
421+
arel_column(column_name)
422+
end
423+
end
424+
413425
private
414426
def all_attributes?(column_names)
415427
(column_names.map(&:to_s) - model.attribute_names - model.attribute_aliases.keys).empty?
@@ -457,17 +469,6 @@ def possible_aggregation?(column_names)
457469
end
458470
end
459471

460-
def aggregate_column(column_name)
461-
case column_name
462-
when Arel::Expressions
463-
column_name
464-
when :all
465-
Arel.star
466-
else
467-
arel_column(column_name)
468-
end
469-
end
470-
471472
def operation_over_aggregate_column(column, operation, distinct)
472473
operation == "count" ? column.count(distinct) : column.public_send(operation)
473474
end
@@ -483,7 +484,7 @@ def execute_simple_calculation(operation, column_name, distinct) # :nodoc:
483484
# PostgreSQL doesn't like ORDER BY when there are no GROUP BY
484485
relation = unscope(:order).distinct!(false)
485486

486-
column = aggregate_column(column_name)
487+
column = relation.aggregate_column(column_name)
487488
select_value = operation_over_aggregate_column(column, operation, distinct)
488489
select_value.distinct = true if operation == "sum" && distinct
489490

@@ -532,7 +533,9 @@ def execute_grouped_calculation(operation, column_name, distinct) # :nodoc:
532533
}
533534
group_columns = group_aliases.zip(group_fields)
534535

535-
column = aggregate_column(column_name)
536+
relation = except(:group).distinct!(false)
537+
538+
column = relation.aggregate_column(column_name)
536539
column_alias = column_alias_tracker.alias_for("#{operation} #{column_name.to_s.downcase}")
537540
select_value = operation_over_aggregate_column(column, operation, distinct)
538541
select_value.as(model.adapter_class.quote_column_name(column_alias))
@@ -549,7 +552,6 @@ def execute_grouped_calculation(operation, column_name, distinct) # :nodoc:
549552
end
550553
}
551554

552-
relation = except(:group).distinct!(false)
553555
relation.group_values = group_fields
554556
relation.select_values = select_values
555557

@@ -666,7 +668,7 @@ def build_count_subquery(relation, column_name, distinct)
666668
relation.unscope!(:order)
667669
else
668670
column_alias = Arel.sql("count_column")
669-
relation.select_values = [ aggregate_column(column_name).as(column_alias) ]
671+
relation.select_values = [ relation.aggregate_column(column_name).as(column_alias) ]
670672
end
671673

672674
subquery_alias = Arel.sql("subquery_for_count", retryable: true)

activerecord/test/cases/calculations_test.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,18 @@ def test_should_sum_arel_attribute
4141
assert_async_equal 318, Account.async_sum(Account.arel_table[:credit_limit])
4242
end
4343

44+
def test_should_sum_with_qualified_name_on_loaded
45+
accounts = Account.all
46+
47+
assert_not_predicate accounts, :loaded?
48+
assert_equal 318, accounts.sum("accounts.credit_limit")
49+
50+
accounts.load
51+
52+
assert_predicate accounts, :loaded?
53+
assert_equal 318, accounts.sum("accounts.credit_limit")
54+
end
55+
4456
def test_should_average_field
4557
assert_equal 53.0, Account.average(:credit_limit)
4658
assert_async_equal 53.0, Account.async_average(:credit_limit)

0 commit comments

Comments
 (0)