Add `time` option to `#touch`

Fixes #18905. `#touch` now takes time as an option. Setting the option
saves the record with the updated_at/on attributes set to the current time
or the time specified. Updated tests and documentation accordingly.
This commit is contained in:
Hyonjee Joo 2015-02-16 01:30:41 -05:00
parent 28fccad2c4
commit 219d71fb90
3 changed files with 34 additions and 6 deletions

View File

@ -1,3 +1,8 @@
* `:time` option added for `#touch`
Fixes #18905.
*Hyonjee Joo*
* Deprecated passing of `start` value to `find_in_batches` and `find_each`
in favour of `begin_at` value.

View File

@ -429,14 +429,17 @@ module ActiveRecord
self
end
# Saves the record with the updated_at/on attributes set to the current time.
# Saves the record with the updated_at/on attributes set to the current time
# or the time specified.
# Please note that no validation is performed and only the +after_touch+,
# +after_commit+ and +after_rollback+ callbacks are executed.
#
# This method can be passed attribute names and an optional time argument.
# If attribute names are passed, they are updated along with updated_at/on
# attributes.
# attributes. If no time argument is passed, the current time is used as default.
#
# product.touch # updates updated_at/on
# product.touch # updates updated_at/on with current time
# product.touch(time: Time.new(2015, 2, 16, 0, 0, 0)) # updates updated_at/on with specified time
# product.touch(:designed_at) # updates the designed_at attribute and updated_at/on
# product.touch(:started_at, :ended_at) # updates started_at, ended_at and updated_at/on attributes
#
@ -460,19 +463,18 @@ module ActiveRecord
# ball = Ball.new
# ball.touch(:updated_at) # => raises ActiveRecordError
#
def touch(*names)
def touch(*names, time: current_time_from_proper_timezone)
raise ActiveRecordError, "cannot touch on a new record object" unless persisted?
attributes = timestamp_attributes_for_update_in_model
attributes.concat(names)
unless attributes.empty?
current_time = current_time_from_proper_timezone
changes = {}
attributes.each do |column|
column = column.to_s
changes[column] = write_attribute(column, current_time)
changes[column] = write_attribute(column, time)
end
changes[self.class.locking_column] = increment_lock if locking_enabled?

View File

@ -73,6 +73,15 @@ class TimestampTest < ActiveRecord::TestCase
assert_equal @previously_updated_at, @developer.updated_at
end
def test_touching_updates_timestamp_with_given_time
previously_updated_at = @developer.updated_at
new_time = Time.utc(2015, 2, 16, 0, 0, 0)
@developer.touch(time: new_time)
assert_not_equal previously_updated_at, @developer.updated_at
assert_equal new_time, @developer.updated_at
end
def test_touching_an_attribute_updates_timestamp
previously_created_at = @developer.created_at
@developer.touch(:created_at)
@ -91,6 +100,18 @@ class TimestampTest < ActiveRecord::TestCase
assert_in_delta Time.now, task.ending, 1
end
def test_touching_an_attribute_updates_timestamp_with_given_time
previously_updated_at = @developer.updated_at
previously_created_at = @developer.created_at
new_time = Time.utc(2015, 2, 16, 4, 54, 0)
@developer.touch(:created_at, time: new_time)
assert_not_equal previously_created_at, @developer.created_at
assert_not_equal previously_updated_at, @developer.updated_at
assert_equal new_time, @developer.created_at
assert_equal new_time, @developer.updated_at
end
def test_touching_many_attributes_updates_them
task = Task.first
previous_starting = task.starting