aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--activerecord/CHANGELOG.md7
-rw-r--r--activerecord/lib/active_record/callbacks.rb2
-rw-r--r--activerecord/lib/active_record/persistence.rb12
-rw-r--r--activerecord/lib/active_record/timestamp.rb6
-rw-r--r--activerecord/test/cases/persistence_test.rb31
5 files changed, 48 insertions, 10 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 4a954c2cc6..6c2a8e63f8 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,10 @@
+* Provide :touch option to save() to accommodate saving without updating
+ timestamps.
+
+ Fixes #18202
+
+ *Dan Olson*
+
* Provide a more helpful error message when an unsupported class is passed to
`serialize`
diff --git a/activerecord/lib/active_record/callbacks.rb b/activerecord/lib/active_record/callbacks.rb
index 523d492a48..497ce8c15c 100644
--- a/activerecord/lib/active_record/callbacks.rb
+++ b/activerecord/lib/active_record/callbacks.rb
@@ -298,7 +298,7 @@ module ActiveRecord
private
- def create_or_update #:nodoc:
+ def create_or_update(*) #:nodoc:
_run_save_callbacks { super }
end
diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb
index bb1d01d089..ded190c111 100644
--- a/activerecord/lib/active_record/persistence.rb
+++ b/activerecord/lib/active_record/persistence.rb
@@ -116,8 +116,8 @@ module ActiveRecord
#
# Attributes marked as readonly are silently ignored if the record is
# being updated.
- def save(*)
- create_or_update
+ def save(*args)
+ create_or_update(*args)
rescue ActiveRecord::RecordInvalid
false
end
@@ -138,8 +138,8 @@ module ActiveRecord
#
# Attributes marked as readonly are silently ignored if the record is
# being updated.
- def save!(*)
- create_or_update || raise(RecordNotSaved.new(nil, self))
+ def save!(*args)
+ create_or_update(*args) || raise(RecordNotSaved.new(nil, self))
end
# Deletes the record in the database and freezes this instance to
@@ -498,9 +498,9 @@ module ActiveRecord
relation
end
- def create_or_update
+ def create_or_update(*args)
raise ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
- result = new_record? ? _create_record : _update_record
+ result = new_record? ? _create_record : _update_record(*args)
result != false
end
diff --git a/activerecord/lib/active_record/timestamp.rb b/activerecord/lib/active_record/timestamp.rb
index 936a18d99a..4d1d7310af 100644
--- a/activerecord/lib/active_record/timestamp.rb
+++ b/activerecord/lib/active_record/timestamp.rb
@@ -57,8 +57,8 @@ module ActiveRecord
super
end
- def _update_record(*args)
- if should_record_timestamps?
+ def _update_record(*args, touch: true, **options)
+ if touch && should_record_timestamps?
current_time = current_time_from_proper_timezone
timestamp_attributes_for_update_in_model.each do |column|
@@ -67,7 +67,7 @@ module ActiveRecord
write_attribute(column, current_time)
end
end
- super
+ super *args
end
def should_record_timestamps?
diff --git a/activerecord/test/cases/persistence_test.rb b/activerecord/test/cases/persistence_test.rb
index 6fc4731f01..cf5a5de3a0 100644
--- a/activerecord/test/cases/persistence_test.rb
+++ b/activerecord/test/cases/persistence_test.rb
@@ -878,4 +878,35 @@ class PersistenceTest < ActiveRecord::TestCase
assert_equal "Welcome to the weblog", post.title
assert_not post.new_record?
end
+
+ class SaveTest < ActiveRecord::TestCase
+ self.use_transactional_fixtures = false
+
+ def test_save_touch_false
+ widget = Class.new(ActiveRecord::Base) do
+ connection.create_table :widgets, force: true do |t|
+ t.string :name
+ t.timestamps null: false
+ end
+
+ self.table_name = :widgets
+ end
+
+ instance = widget.create!({
+ name: 'Bob',
+ created_at: 1.day.ago,
+ updated_at: 1.day.ago
+ })
+
+ created_at = instance.created_at
+ updated_at = instance.updated_at
+
+ instance.name = 'Barb'
+ instance.save!(touch: false)
+ assert_equal instance.created_at, created_at
+ assert_equal instance.updated_at, updated_at
+ ensure
+ ActiveRecord::Base.connection.drop_table :widgets
+ end
+ end
end