From e672575906073d2b1f1b7d7a4e6cccf80fc18ce2 Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Mon, 10 May 2021 11:05:02 +0200 Subject: [PATCH] Allow Relation#sum to take an `init` parameters This is needed to not prevent full use of `Enumerable#sum` on `Relation` objects. --- .../active_record/relation/calculations.rb | 19 ++++++++++++++----- activerecord/test/cases/calculations_test.rb | 14 ++++++++------ 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index a2f6189bc3..1d040d4e9e 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -83,15 +83,24 @@ module ActiveRecord # #calculate for examples with options. # # Person.sum(:age) # => 4562 - def sum(column_name = nil) + def sum(identity_or_column = nil, &block) if block_given? - unless column_name.nil? - raise ArgumentError, "Column name argument is not supported when a block is passed." + values = map(&block) + if identity_or_column.nil? && (values.first.is_a?(Numeric) || values.first(1) == []) + identity_or_column = 0 end - super() + if identity_or_column.nil? + ActiveSupport::Deprecation.warn(<<-MSG.squish) + Rails 7.0 has deprecated Enumerable.sum in favor of Ruby's native implementation available since 2.4. + Sum of non-numeric elements requires an initial argument. + MSG + values.inject(:+) || 0 + else + values.sum(identity_or_column) + end else - calculate(:sum, column_name) + calculate(:sum, identity_or_column) end end diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb index 74d2c67fd4..b22b8eabf1 100644 --- a/activerecord/test/cases/calculations_test.rb +++ b/activerecord/test/cases/calculations_test.rb @@ -503,7 +503,15 @@ class CalculationsTest < ActiveRecord::TestCase end def test_should_not_overshadow_enumerable_sum + some_companies = companies(:rails_core).companies.order(:id) + assert_equal 6, [1, 2, 3].sum(&:abs) + assert_equal 15, some_companies.sum(&:id) + assert_equal 25, some_companies.sum(10, &:id) + assert_deprecated do + assert_equal "LeetsoftJadedpixel", some_companies.sum(&:name) + end + assert_equal "companies: LeetsoftJadedpixel", some_companies.sum("companies: ", &:name) end def test_should_sum_scoped_field @@ -1341,12 +1349,6 @@ class CalculationsTest < ActiveRecord::TestCase end end - def test_sum_with_block_and_column_name_raises_an_error - assert_raises(ArgumentError) do - Account.sum(:firm_id) { 1 } - end - end - test "#skip_query_cache! for #pluck" do Account.cache do assert_queries(1) do