Use `to_formatted_s(:db)` instead of `to_s(:db)` internally

Ruby 3.1 introduced an optimization to string interpolation for some
core classes in b08dacfea3.

But since we override `to_s` in some of those core classes to add behavior
like `to_s(:db)`, all Rails applications will not be able to take advantage
of that improvement.

Since we can use the `to_formatted_s` alias for the Rails specific behavior
it is best for us to deprecate the `to_s` core extension and allow Rails
applications to get the proformace improvement.

This commit starts removing all the `to_s(:db)` calls inside the framework
so we can deprecate the core extension in the next commit.
This commit is contained in:
Rafael Mendonça França 2021-11-24 22:41:33 +00:00
parent d301b3b02b
commit c2e12e0191
No known key found for this signature in database
GPG Key ID: FC23B6D0F1EEE948
26 changed files with 65 additions and 64 deletions

View File

@ -3,7 +3,7 @@ witty_retort:
topic_id: 1
developer_id: 1
content: Birdman is better!
created_at: <%= 6.hours.ago.to_s(:db) %>
created_at: <%= 6.hours.ago.to_formatted_s(:db) %>
updated_at: nil
another:
@ -11,5 +11,5 @@ another:
topic_id: 2
developer_id: 1
content: Nuh uh!
created_at: <%= 1.hour.ago.to_s(:db) %>
created_at: <%= 1.hour.ago.to_formatted_s(:db) %>
updated_at: nil

View File

@ -3,7 +3,7 @@ futurama:
title: Isn't futurama awesome?
subtitle: It really is, isn't it.
content: I like futurama
created_at: <%= 1.day.ago.to_s(:db) %>
created_at: <%= 1.day.ago.to_formatted_s(:db) %>
updated_at:
harvey_birdman:
@ -11,7 +11,7 @@ harvey_birdman:
title: Harvey Birdman is the king of all men
subtitle: yup
content: It really is
created_at: <%= 2.hours.ago.to_s(:db) %>
created_at: <%= 2.hours.ago.to_formatted_s(:db) %>
updated_at:
rails:
@ -19,4 +19,4 @@ rails:
title: Rails is nice
subtitle: It makes me happy
content: except when I have to hack internals to fix pagination. even then really.
created_at: <%= 20.minutes.ago.to_s(:db) %>
created_at: <%= 20.minutes.ago.to_formatted_s(:db) %>

View File

@ -11,7 +11,7 @@ module ActiveModel
end
def type_cast_for_schema(value)
value.to_s(:db).inspect
value.to_formatted_s(:db).inspect
end
private

View File

@ -36,7 +36,7 @@ module ActiveModel
end
def type_cast_for_schema(value)
value.to_s(:db).inspect
value.to_formatted_s(:db).inspect
end
def user_input_in_time_zone(value)

View File

@ -128,7 +128,7 @@ module ActiveRecord
end
end
result = value.to_s(:db)
result = value.to_formatted_s(:db)
if value.respond_to?(:usec) && value.usec > 0
result << "." << sprintf("%06d", value.usec)
else

View File

@ -407,7 +407,7 @@ module ActiveRecord
# defaults:
#
# DEFAULTS: &DEFAULTS
# created_on: <%= 3.weeks.ago.to_s(:db) %>
# created_on: <%= 3.weeks.ago.to_formatted_s(:db) %>
#
# first:
# name: Smurf

View File

@ -57,7 +57,7 @@ class SQLite3QuotingTest < ActiveRecord::SQLite3TestCase
t = Time.new(2000, 7, 1, 0, 0, 0, "+04:30")
expected = t.change(year: 2000, month: 1, day: 1)
expected = expected.getutc.to_s(:db).sub(/\A\d\d\d\d-\d\d-\d\d /, "2000-01-01 ")
expected = expected.getutc.to_formatted_s(:db).sub(/\A\d\d\d\d-\d\d-\d\d /, "2000-01-01 ")
assert_equal expected, @conn.quoted_time(t)
end
@ -70,7 +70,7 @@ class SQLite3QuotingTest < ActiveRecord::SQLite3TestCase
t = Time.new(2000, 7, 1, 0, 0, 0, "+04:30")
expected = t.change(year: 2000, month: 1, day: 1)
expected = expected.getlocal.to_s(:db).sub(/\A\d\d\d\d-\d\d-\d\d /, "2000-01-01 ")
expected = expected.getlocal.to_formatted_s(:db).sub(/\A\d\d\d\d-\d\d-\d\d /, "2000-01-01 ")
assert_equal expected, @conn.quoted_time(t)
end

View File

@ -107,8 +107,8 @@ class MultiParameterAttributeTest < ActiveRecord::TestCase
}
topic = Topic.find(1)
topic.attributes = attributes
# testing against to_s(:db) representation because either a Time or a DateTime might be returned, depending on platform
assert_equal "1850-06-24 16:24:00", topic.written_on.to_s(:db)
# testing against to_formatted_s(:db) representation because either a Time or a DateTime might be returned, depending on platform
assert_equal "1850-06-24 16:24:00", topic.written_on.to_formatted_s(:db)
end
def test_multiparameter_attributes_on_time_will_raise_on_big_time_if_missing_date_parts

View File

@ -43,20 +43,20 @@ module ActiveRecord
def test_quoted_date
t = Date.today
assert_equal t.to_s(:db), @quoter.quoted_date(t)
assert_equal t.to_formatted_s(:db), @quoter.quoted_date(t)
end
def test_quoted_timestamp_utc
with_timezone_config default: :utc do
t = Time.now.change(usec: 0)
assert_equal t.getutc.to_s(:db), @quoter.quoted_date(t)
assert_equal t.getutc.to_formatted_s(:db), @quoter.quoted_date(t)
end
end
def test_quoted_timestamp_local
with_timezone_config default: :local do
t = Time.now.change(usec: 0)
assert_equal t.getlocal.to_s(:db), @quoter.quoted_date(t)
assert_equal t.getlocal.to_formatted_s(:db), @quoter.quoted_date(t)
end
end
@ -65,7 +65,7 @@ module ActiveRecord
t = Time.now.change(usec: 0)
expected = t.change(year: 2000, month: 1, day: 1)
expected = expected.getutc.to_s(:db).slice(11..-1)
expected = expected.getutc.to_formatted_s(:db).slice(11..-1)
assert_equal expected, @quoter.quoted_time(t)
end
@ -76,7 +76,7 @@ module ActiveRecord
t = Time.now.change(usec: 0)
expected = t.change(year: 2000, month: 1, day: 1)
expected = expected.getlocal.to_s(:db).sub("2000-01-01 ", "")
expected = expected.getlocal.to_formatted_s(:db).sub("2000-01-01 ", "")
assert_equal expected, @quoter.quoted_time(t)
end
@ -88,7 +88,7 @@ module ActiveRecord
t = Time.new(2000, 7, 1, 0, 0, 0, "+04:30")
expected = t.change(year: 2000, month: 1, day: 1)
expected = expected.getutc.to_s(:db).slice(11..-1)
expected = expected.getutc.to_formatted_s(:db).slice(11..-1)
assert_equal expected, @quoter.quoted_time(t)
end
@ -101,7 +101,7 @@ module ActiveRecord
t = Time.new(2000, 7, 1, 0, 0, 0, "+04:30")
expected = t.change(year: 2000, month: 1, day: 1)
expected = expected.getlocal.to_s(:db).slice(11..-1)
expected = expected.getlocal.to_formatted_s(:db).slice(11..-1)
assert_equal expected, @quoter.quoted_time(t)
end
@ -111,7 +111,7 @@ module ActiveRecord
def test_quoted_datetime_utc
with_timezone_config default: :utc do
t = Time.now.change(usec: 0).to_datetime
assert_equal t.getutc.to_s(:db), @quoter.quoted_date(t)
assert_equal t.getutc.to_formatted_s(:db), @quoter.quoted_date(t)
end
end
@ -120,7 +120,7 @@ module ActiveRecord
def test_quoted_datetime_local
with_timezone_config default: :local do
t = Time.now.change(usec: 0).to_datetime
assert_equal t.to_s(:db), @quoter.quoted_date(t)
assert_equal t.to_formatted_s(:db), @quoter.quoted_date(t)
end
end

View File

@ -1,40 +1,40 @@
membership_of_boring_club:
joined_on: <%= 3.weeks.ago.to_s(:db) %>
joined_on: <%= 3.weeks.ago.to_formatted_s(:db) %>
club: boring_club
member_id: 1
favorite: false
type: CurrentMembership
membership_of_favorite_club:
joined_on: <%= 3.weeks.ago.to_s(:db) %>
joined_on: <%= 3.weeks.ago.to_formatted_s(:db) %>
club: moustache_club
member_id: 1
favorite: true
type: Membership
other_guys_membership:
joined_on: <%= 4.weeks.ago.to_s(:db) %>
joined_on: <%= 4.weeks.ago.to_formatted_s(:db) %>
club: boring_club
member_id: 2
favorite: false
type: CurrentMembership
blarpy_winkup_outrageous_club:
joined_on: <%= 4.weeks.ago.to_s(:db) %>
joined_on: <%= 4.weeks.ago.to_formatted_s(:db) %>
club: outrageous_club
member_id: 3
favorite: false
type: CurrentMembership
super_membership_of_boring_club:
joined_on: <%= 3.weeks.ago.to_s(:db) %>
joined_on: <%= 3.weeks.ago.to_formatted_s(:db) %>
club: boring_club
member_id: 1
favorite: false
type: SuperMembership
selected_membership_of_boring_club:
joined_on: <%= 3.weeks.ago.to_s(:db) %>
joined_on: <%= 3.weeks.ago.to_formatted_s(:db) %>
club: boring_club
member_id: 1
favorite: false

View File

@ -5,8 +5,8 @@ blackbeard:
redbeard:
catchphrase: "Avast!"
parrot: louis
created_on: "<%= 2.weeks.ago.to_s(:db) %>"
updated_on: "<%= 2.weeks.ago.to_s(:db) %>"
created_on: "<%= 2.weeks.ago.to_formatted_s(:db) %>"
updated_on: "<%= 2.weeks.ago.to_formatted_s(:db) %>"
mark:
catchphrase: "X $LABELs the spot!"

View File

@ -27,7 +27,7 @@ class Date
# date = Date.new(2007, 11, 10) # => Sat, 10 Nov 2007
#
# date.to_formatted_s(:db) # => "2007-11-10"
# date.to_s(:db) # => "2007-11-10"
# date.to_formatted_s(:db) # => "2007-11-10"
#
# date.to_formatted_s(:short) # => "10 Nov"
# date.to_formatted_s(:number) # => "20071110"

View File

@ -15,7 +15,7 @@ class DateTime
# datetime = DateTime.civil(2007, 12, 4, 0, 0, 0, 0) # => Tue, 04 Dec 2007 00:00:00 +0000
#
# datetime.to_formatted_s(:db) # => "2007-12-04 00:00:00"
# datetime.to_s(:db) # => "2007-12-04 00:00:00"
# datetime.to_formatted_s(:db) # => "2007-12-04 00:00:00"
# datetime.to_s(:number) # => "20071204000000"
# datetime.to_formatted_s(:short) # => "04 Dec 00:00"
# datetime.to_formatted_s(:long) # => "December 04, 2007 00:00"

View File

@ -132,6 +132,7 @@ module ActiveSupport
super(format)
end
end
alias_method :to_formatted_s, :to_s
end
end

View File

@ -7,7 +7,7 @@ module ActiveSupport
case start
when String then "BETWEEN '#{start}' AND '#{stop}'"
else
"BETWEEN '#{start.to_s(:db)}' AND '#{stop.to_s(:db)}'"
"BETWEEN '#{start.to_formatted_s(:db)}' AND '#{stop.to_formatted_s(:db)}'"
end
end
}
@ -17,14 +17,14 @@ module ActiveSupport
# range = (1..100) # => 1..100
#
# range.to_s # => "1..100"
# range.to_s(:db) # => "BETWEEN '1' AND '100'"
# range.to_formatted_s(:db) # => "BETWEEN '1' AND '100'"
#
# == Adding your own range formats to to_s
# You can add your own formats to the Range::RANGE_FORMATS hash.
# Use the format name as the hash key and a Proc instance.
#
# # config/initializers/range_formats.rb
# Range::RANGE_FORMATS[:short] = ->(start, stop) { "Between #{start.to_s(:db)} and #{stop.to_s(:db)}" }
# Range::RANGE_FORMATS[:short] = ->(start, stop) { "Between #{start.to_formatted_s(:db)} and #{stop.to_formatted_s(:db)}" }
def to_s(format = :default)
if formatter = RANGE_FORMATS[format]
formatter.call(first, last)

View File

@ -54,7 +54,7 @@ module ActiveSupport
FORMATTING = {
"symbol" => Proc.new { |symbol| symbol.to_s },
"date" => Proc.new { |date| date.to_s(:db) },
"date" => Proc.new { |date| date.to_formatted_s(:db) },
"dateTime" => Proc.new { |time| time.xmlschema },
"binary" => Proc.new { |binary| ::Base64.encode64(binary) },
"yaml" => Proc.new { |yaml| yaml.to_yaml }

View File

@ -88,8 +88,8 @@ class ToSTest < ActiveSupport::TestCase
def test_to_s_db
collection = [TestDB.new, TestDB.new, TestDB.new]
assert_equal "null", [].to_s(:db)
assert_equal "1,2,3", collection.to_s(:db)
assert_equal "null", [].to_formatted_s(:db)
assert_equal "1,2,3", collection.to_formatted_s(:db)
end
end

View File

@ -27,7 +27,7 @@ class DateExtCalculationsTest < ActiveSupport::TestCase
assert_equal "21 Feb", date.to_s(:short)
assert_equal "February 21, 2005", date.to_s(:long)
assert_equal "February 21st, 2005", date.to_s(:long_ordinal)
assert_equal "2005-02-21", date.to_s(:db)
assert_equal "2005-02-21", date.to_formatted_s(:db)
assert_equal "2005-02-21", date.to_s(:inspect)
assert_equal "21 Feb 2005", date.to_s(:rfc822)
assert_equal "2005-02-21", date.to_s(:iso8601)
@ -39,7 +39,7 @@ class DateExtCalculationsTest < ActiveSupport::TestCase
assert_equal "01 Feb", date.to_s(:short)
assert_equal "February 01, 2005", date.to_s(:long)
assert_equal "February 1st, 2005", date.to_s(:long_ordinal)
assert_equal "2005-02-01", date.to_s(:db)
assert_equal "2005-02-01", date.to_formatted_s(:db)
assert_equal "2005-02-01", date.to_s(:inspect)
assert_equal "01 Feb 2005", date.to_s(:rfc822)
assert_equal "2005-02-01", date.to_s(:iso8601)

View File

@ -15,7 +15,7 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase
def test_to_s
datetime = DateTime.new(2005, 2, 21, 14, 30, 0, 0)
assert_equal "2005-02-21 14:30:00", datetime.to_s(:db)
assert_equal "2005-02-21 14:30:00", datetime.to_formatted_s(:db)
assert_equal "2005-02-21 14:30:00.000000000 +0000", datetime.to_s(:inspect)
assert_equal "14:30", datetime.to_s(:time)
assert_equal "21 Feb 14:30", datetime.to_s(:short)

View File

@ -8,22 +8,22 @@ require "active_support/core_ext/range"
class RangeTest < ActiveSupport::TestCase
def test_to_s_from_dates
date_range = Date.new(2005, 12, 10)..Date.new(2005, 12, 12)
assert_equal "BETWEEN '2005-12-10' AND '2005-12-12'", date_range.to_s(:db)
assert_equal "BETWEEN '2005-12-10' AND '2005-12-12'", date_range.to_formatted_s(:db)
end
def test_to_s_from_times
date_range = Time.utc(2005, 12, 10, 15, 30)..Time.utc(2005, 12, 10, 17, 30)
assert_equal "BETWEEN '2005-12-10 15:30:00' AND '2005-12-10 17:30:00'", date_range.to_s(:db)
assert_equal "BETWEEN '2005-12-10 15:30:00' AND '2005-12-10 17:30:00'", date_range.to_formatted_s(:db)
end
def test_to_s_with_alphabets
alphabet_range = ("a".."z")
assert_equal "BETWEEN 'a' AND 'z'", alphabet_range.to_s(:db)
assert_equal "BETWEEN 'a' AND 'z'", alphabet_range.to_formatted_s(:db)
end
def test_to_s_with_numeric
number_range = (1..100)
assert_equal "BETWEEN '1' AND '100'", number_range.to_s(:db)
assert_equal "BETWEEN '1' AND '100'", number_range.to_formatted_s(:db)
end
def test_date_range

View File

@ -583,7 +583,7 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase
time = Time.utc(2005, 2, 21, 17, 44, 30.12345678901)
assert_equal time.to_default_s, time.to_s
assert_equal time.to_default_s, time.to_s(:doesnt_exist)
assert_equal "2005-02-21 17:44:30", time.to_s(:db)
assert_equal "2005-02-21 17:44:30", time.to_formatted_s(:db)
assert_equal "21 Feb 17:44", time.to_s(:short)
assert_equal "17:44", time.to_s(:time)
assert_equal "20050221174430", time.to_s(:number)

View File

@ -138,7 +138,7 @@ class TimeWithZoneTest < ActiveSupport::TestCase
end
def test_to_s_db
assert_equal "2000-01-01 00:00:00", @twz.to_s(:db)
assert_equal "2000-01-01 00:00:00", @twz.to_formatted_s(:db)
end
def test_to_s_inspect

View File

@ -18,9 +18,9 @@ class TimeTravelTest < ActiveSupport::TestCase
expected_time = Time.now + 1.day
travel 1.day
assert_equal expected_time.to_s(:db), Time.now.to_s(:db)
assert_equal expected_time.to_formatted_s(:db), Time.now.to_formatted_s(:db)
assert_equal expected_time.to_date, Date.today
assert_equal expected_time.to_datetime.to_s(:db), DateTime.now.to_s(:db)
assert_equal expected_time.to_datetime.to_formatted_s(:db), DateTime.now.to_formatted_s(:db)
ensure
travel_back
end
@ -31,14 +31,14 @@ class TimeTravelTest < ActiveSupport::TestCase
expected_time = Time.now + 1.day
travel 1.day do
assert_equal expected_time.to_s(:db), Time.now.to_s(:db)
assert_equal expected_time.to_formatted_s(:db), Time.now.to_formatted_s(:db)
assert_equal expected_time.to_date, Date.today
assert_equal expected_time.to_datetime.to_s(:db), DateTime.now.to_s(:db)
assert_equal expected_time.to_datetime.to_formatted_s(:db), DateTime.now.to_formatted_s(:db)
end
assert_not_equal expected_time.to_s(:db), Time.now.to_s(:db)
assert_not_equal expected_time.to_formatted_s(:db), Time.now.to_formatted_s(:db)
assert_not_equal expected_time.to_date, Date.today
assert_not_equal expected_time.to_datetime.to_s(:db), DateTime.now.to_s(:db)
assert_not_equal expected_time.to_datetime.to_formatted_s(:db), DateTime.now.to_formatted_s(:db)
end
end
@ -78,7 +78,7 @@ class TimeTravelTest < ActiveSupport::TestCase
expected_time = 5.minutes.ago
travel_to 5.minutes.ago do
assert_equal expected_time.to_s(:db), Time.zone.now.to_s(:db)
assert_equal expected_time.to_formatted_s(:db), Time.zone.now.to_formatted_s(:db)
end
end
end
@ -92,7 +92,7 @@ class TimeTravelTest < ActiveSupport::TestCase
expected_time = Time.new(2004, 11, 24, 1, 4, 44)
travel_to "2004-11-24 01:04:44" do
assert_equal expected_time.to_s(:db), Time.zone.now.to_s(:db)
assert_equal expected_time.to_formatted_s(:db), Time.zone.now.to_formatted_s(:db)
end
end
end
@ -237,7 +237,7 @@ class TimeTravelTest < ActiveSupport::TestCase
freeze_time
sleep(1)
assert_equal expected_time.to_s(:db), Time.now.to_s(:db)
assert_equal expected_time.to_formatted_s(:db), Time.now.to_formatted_s(:db)
ensure
travel_back
end
@ -248,10 +248,10 @@ class TimeTravelTest < ActiveSupport::TestCase
freeze_time do
sleep(1)
assert_equal expected_time.to_s(:db), Time.now.to_s(:db)
assert_equal expected_time.to_formatted_s(:db), Time.now.to_formatted_s(:db)
end
assert_operator expected_time.to_s(:db), :<, Time.now.to_s(:db)
assert_operator expected_time.to_formatted_s(:db), :<, Time.now.to_formatted_s(:db)
end
def test_time_helper_unfreeze_time

View File

@ -216,7 +216,7 @@ One possibility is to set the expiry time-stamp of the cookie with the session I
```ruby
class Session < ApplicationRecord
def self.sweep(time = 1.hour)
where("updated_at < ?", time.ago.to_s(:db)).delete_all
where("updated_at < ?", time.ago.to_formatted_s(:db)).delete_all
end
end
```
@ -224,7 +224,7 @@ end
The section about session fixation introduced the problem of maintained sessions. An attacker maintaining a session every five minutes can keep the session alive forever, although you are expiring sessions. A simple solution for this would be to add a `created_at` column to the sessions table. Now you can delete sessions that were created a long time ago. Use this line in the sweep method above:
```ruby
where("updated_at < ? OR created_at < ?", time.ago.to_s(:db), 2.days.ago.to_s(:db)).delete_all
where("updated_at < ? OR created_at < ?", time.ago.to_formatted_s(:db), 2.days.ago.to_formatted_s(:db)).delete_all
```
Cross-Site Request Forgery (CSRF)

View File

@ -123,8 +123,8 @@ module Rails
when :integer then 1
when :float then 1.5
when :decimal then "9.99"
when :datetime, :timestamp, :time then Time.now.to_s(:db)
when :date then Date.today.to_s(:db)
when :datetime, :timestamp, :time then Time.now.to_formatted_s(:db)
when :date then Date.today.to_formatted_s(:db)
when :string then name == "type" ? "" : "MyString"
when :text then "MyText"
when :boolean then false

View File

@ -91,12 +91,12 @@ class GeneratedAttributeTest < Rails::Generators::TestCase
def test_default_value_is_datetime
%w(datetime timestamp time).each do |attribute_type|
assert_field_default_value attribute_type, Time.now.to_s(:db)
assert_field_default_value attribute_type, Time.now.to_formatted_s(:db)
end
end
def test_default_value_is_date
assert_field_default_value :date, Date.today.to_s(:db)
assert_field_default_value :date, Date.today.to_formatted_s(:db)
end
def test_default_value_is_string