1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Introduce _update_row to decouple optimistic locking concern from Persistence module

This commit is contained in:
Ryuta Kamizono 2018-03-03 18:44:09 +09:00
parent ea45d56d3d
commit ae2d36cf21
2 changed files with 45 additions and 28 deletions

View file

@ -111,6 +111,37 @@ module ActiveRecord
end
end
def _update_row(attribute_names, attempted_action)
return super unless locking_enabled?
begin
locking_column = self.class.locking_column
previous_lock_value = read_attribute_before_type_cast(locking_column)
attribute_names << locking_column
self[locking_column] += 1
affected_rows = self.class._update_record(
attributes_with_values(attribute_names),
self.class.primary_key => id_in_database,
locking_column => previous_lock_value
)
if affected_rows != 1
raise ActiveRecord::StaleObjectError.new(self, attempted_action)
end
affected_rows
# If something went wrong, revert the locking_column value.
rescue Exception
self[locking_column] = previous_lock_value
raise
ensure
clear_attribute_change(locking_column)
end
end
def destroy_row
return super unless locking_enabled?

View file

@ -663,31 +663,12 @@ module ActiveRecord
unless attribute_names.empty?
attribute_names.each do |attr_name|
write_attribute(attr_name, time)
clear_attribute_change(attr_name)
end
constraints = { self.class.primary_key => id_in_database }
affected_rows = _update_row(attribute_names, "touch")
if locking_enabled?
locking_column = self.class.locking_column
constraints[locking_column] = read_attribute_before_type_cast(locking_column)
attribute_names << locking_column
increment_lock
end
clear_attribute_changes(attribute_names)
affected_rows = self.class._update_record(
attributes_with_values_for_update(attribute_names),
constraints
)
result = affected_rows == 1
if !result && locking_enabled?
raise ActiveRecord::StaleObjectError.new(self, "touch")
end
@_trigger_update_callback = result
@_trigger_update_callback = affected_rows == 1
else
true
end
@ -707,6 +688,13 @@ module ActiveRecord
self.class._delete_record(self.class.primary_key => id_in_database)
end
def _update_row(attribute_names, attempted_action)
self.class._update_record(
attributes_with_values(attribute_names),
self.class.primary_key => id_in_database
)
end
def create_or_update(*args, &block)
_raise_readonly_record_error if readonly?
return false if destroyed?
@ -718,15 +706,13 @@ module ActiveRecord
# Returns the number of affected rows.
def _update_record(attribute_names = self.attribute_names)
attribute_names &= self.class.column_names
attributes_values = attributes_with_values_for_update(attribute_names)
if attributes_values.empty?
attribute_names = attributes_for_update(attribute_names)
if attribute_names.empty?
affected_rows = 0
@_trigger_update_callback = true
else
affected_rows = self.class._update_record(
attributes_values,
self.class.primary_key => id_in_database
)
affected_rows = _update_row(attribute_names, "update")
@_trigger_update_callback = affected_rows == 1
end