Skip to content

Commit 7db044f

Browse files
committed
Merge pull request rails#46243 from shouichi/clear-locking-column-on-dup
Clear locking column on #dup Fix: rails#46243
2 parents fbe60e9 + 13d3fc9 commit 7db044f

File tree

4 files changed

+48
-2
lines changed

4 files changed

+48
-2
lines changed

activerecord/CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
* Clear locking column on #dup
2+
3+
This change fixes not to duplicate locking_column like id and timestamps.
4+
5+
```
6+
car = Car.create!
7+
car.touch
8+
car.lock_version #=> 1
9+
car.dup.lock_version #=> 0
10+
```
11+
12+
*Shouichi Kamiya*, *Seonggi Yang*, *Ryohei UEDA*
13+
114
* Invalidate transaction as early as possible
215
316
After rescuing a `TransactionRollbackError` exception Rails invalidates transactions earlier in the flow

activerecord/lib/active_record/core.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,8 @@ def init_with_attributes(attributes, new_record = false) # :nodoc:
517517
# only, not its associations. The extent of a "deep" copy is application
518518
# specific and is therefore left to the application to implement according
519519
# to its need.
520-
# The dup method does not preserve the timestamps (created|updated)_(at|on).
520+
# The dup method does not preserve the timestamps (created|updated)_(at|on)
521+
# and locking column.
521522

522523
##
523524
def initialize_dup(other) # :nodoc:

activerecord/lib/active_record/locking/optimistic.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ def increment!(*, **) # :nodoc:
6969
end
7070
end
7171

72+
def initialize_dup(other) # :nodoc:
73+
super
74+
_clear_locking_column if locking_enabled?
75+
end
76+
7277
private
7378
def _create_record(attribute_names = self.attribute_names)
7479
if locking_enabled?
@@ -142,6 +147,11 @@ def _lock_value_for_database(locking_column)
142147
end
143148
end
144149

150+
def _clear_locking_column
151+
self[self.class.locking_column] = nil
152+
clear_attribute_change(self.class.locking_column)
153+
end
154+
145155
module ClassMethods
146156
DEFAULT_LOCKING_COLUMN = "lock_version"
147157

activerecord/test/cases/dup_test.rb

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44
require "models/reply"
55
require "models/topic"
66
require "models/movie"
7+
require "models/car"
78

89
module ActiveRecord
910
class DupTest < ActiveRecord::TestCase
10-
fixtures :topics
11+
fixtures :topics, :cars
1112

1213
def test_dup
1314
assert_not_predicate Topic.new.freeze.dup, :frozen?
@@ -118,6 +119,27 @@ def test_dup_timestamps_are_cleared
118119
assert_not_nil new_topic.created_at
119120
end
120121

122+
def test_dup_locking_column_is_cleared
123+
car = Car.first
124+
car.touch
125+
assert_not_equal 0, car.lock_version
126+
127+
car.lock_version = 1000
128+
129+
new_car = car.dup
130+
assert_equal 0, new_car.lock_version
131+
end
132+
133+
def test_dup_locking_column_is_not_dirty
134+
car = Car.first
135+
car.touch
136+
assert_not_equal 0, car.lock_version
137+
138+
car.lock_version += 1
139+
new_car = car.dup
140+
assert_not_predicate new_car, :lock_version_changed?
141+
end
142+
121143
def test_dup_after_initialize_callbacks
122144
topic = Topic.new
123145
assert Topic.after_initialize_called

0 commit comments

Comments
 (0)