Browse files

Added ActiveRecord::Base#touch to update the updated_at/on attributes…

… with the current time [DHH]
  • Loading branch information...
1 parent b49027e commit fdb61f02c54bda0ad5ff6d0259209113202b9307 @dhh dhh committed Apr 16, 2009
Showing with 64 additions and 9 deletions.
  1. +5 −0 activerecord/CHANGELOG
  2. +29 −9 activerecord/lib/active_record/timestamp.rb
  3. +30 −0 activerecord/test/cases/timestamp_test.rb
View
5 activerecord/CHANGELOG
@@ -1,3 +1,8 @@
+*Edge*
+
+* Added ActiveRecord::Base#touch to update the updated_at/on attributes with the current time [DHH]
+
+
*2.3.2 [Final] (March 15, 2009)*
* Added ActiveRecord::Base.find_each and ActiveRecord::Base.find_in_batches for batch processing [DHH/Jamis Buck]
View
38 activerecord/lib/active_record/timestamp.rb
@@ -15,27 +15,47 @@ def self.included(base) #:nodoc:
base.class_inheritable_accessor :record_timestamps, :instance_writer => false
base.record_timestamps = true
end
+
+ # Saves the record with the updated_at/on attributes set to the current time.
+ # If the save fails because of validation errors, an ActiveRecord::RecordInvalid exception is raised.
+ def touch
+ current_time = current_time_from_proper_timezone
+
+ write_attribute('updated_at', current_time) if respond_to?(:updated_at)
+ write_attribute('updated_on', current_time) if respond_to?(:updated_on)
+
+ save!
+ end
+
private
def create_with_timestamps #:nodoc:
if record_timestamps
- t = self.class.default_timezone == :utc ? Time.now.utc : Time.now
- write_attribute('created_at', t) if respond_to?(:created_at) && created_at.nil?
- write_attribute('created_on', t) if respond_to?(:created_on) && created_on.nil?
+ current_time = current_time_from_proper_timezone
+
+ write_attribute('created_at', current_time) if respond_to?(:created_at) && created_at.nil?
+ write_attribute('created_on', current_time) if respond_to?(:created_on) && created_on.nil?
- write_attribute('updated_at', t) if respond_to?(:updated_at) && updated_at.nil?
- write_attribute('updated_on', t) if respond_to?(:updated_on) && updated_on.nil?
+ write_attribute('updated_at', current_time) if respond_to?(:updated_at) && updated_at.nil?
+ write_attribute('updated_on', current_time) if respond_to?(:updated_on) && updated_on.nil?
end
+
create_without_timestamps
end
def update_with_timestamps(*args) #:nodoc:
if record_timestamps && (!partial_updates? || changed?)
- t = self.class.default_timezone == :utc ? Time.now.utc : Time.now
- write_attribute('updated_at', t) if respond_to?(:updated_at)
- write_attribute('updated_on', t) if respond_to?(:updated_on)
+ current_time = current_time_from_proper_timezone
+
+ write_attribute('updated_at', current_time) if respond_to?(:updated_at)
+ write_attribute('updated_on', current_time) if respond_to?(:updated_on)
end
+
update_without_timestamps(*args)
end
+
+ def current_time_from_proper_timezone
+ self.class.default_timezone == :utc ? Time.now.utc : Time.now
+ end
end
-end
+end
View
30 activerecord/test/cases/timestamp_test.rb
@@ -0,0 +1,30 @@
+require 'cases/helper'
+require 'models/developer'
+
+class TimestampTest < ActiveRecord::TestCase
+ fixtures :developers
+
+ def setup
+ @developer = Developer.first
+ @previously_updated_at = @developer.updated_at
+ end
+
+ def test_saving_a_changed_record_updates_its_timestamp
+ @developer.name = "Jack Bauer"
+ @developer.save!
+
+ assert @previously_updated_at != @developer.updated_at
+ end
+
+ def test_saving_a_unchanged_record_doesnt_update_its_timestamp
+ @developer.save!
+
+ assert @previously_updated_at == @developer.updated_at
+ end
+
+ def test_touching_a_record_updates_its_timestamp
+ @developer.touch
+
+ assert @previously_updated_at != @developer.updated_at
+ end
+end

3 comments on commit fdb61f0

@drewblas

I love having a touch method added, but I disagree with the way it functions. I feel that least-surprise would be the following:

.touch should not run the validations, but instead make the change no matter what ( just as if you called model.update_attribute(:updated_at, Time.now) )

.touch! should run the validations and raise an error if it fails ( just like .save! )

@norbert

I agree. Methods that call save! where only something like update_attribute is expected can lead to a good deal of confusion.

Please sign in to comment.