module ActiveRecord::Locking::Optimistic
def _clear_locking_column
def _clear_locking_column self[self.class.locking_column] = nil clear_attribute_change(self.class.locking_column) end
def _create_record(attribute_names = self.attribute_names)
def _create_record(attribute_names = self.attribute_names) if locking_enabled? # We always want to persist the locking version, even if we don't detect # a change from the default, since the database might have no default attribute_names |= [self.class.locking_column] end super end
def _lock_value_for_database(locking_column)
def _lock_value_for_database(locking_column) if will_save_change_to_attribute?(locking_column) @attributes[locking_column].value_for_database else @attributes[locking_column].original_value_for_database end end
def _query_constraints_hash
def _query_constraints_hash return super unless locking_enabled? locking_column = self.class.locking_column super.merge(locking_column => _lock_value_for_database(locking_column)) end
def _touch_row(attribute_names, time)
def _touch_row(attribute_names, time) @_touch_attr_names << self.class.locking_column if locking_enabled? super end
def _update_row(attribute_names, attempted_action = "update")
def _update_row(attribute_names, attempted_action = "update") return super unless locking_enabled? begin locking_column = self.class.locking_column lock_attribute_was = @attributes[locking_column] update_constraints = _query_constraints_hash attribute_names = attribute_names.dup if attribute_names.frozen? attribute_names << locking_column self[locking_column] += 1 affected_rows = self.class._update_record( attributes_with_values(attribute_names), update_constraints ) 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 @attributes[locking_column] = lock_attribute_was raise end end
def destroy_row
def destroy_row affected_rows = super if locking_enabled? && affected_rows != 1 raise ActiveRecord::StaleObjectError.new(self, "destroy") end affected_rows end
def increment!(*, **) # :nodoc:
def increment!(*, **) # :nodoc: super.tap do if locking_enabled? self[self.class.locking_column] += 1 clear_attribute_change(self.class.locking_column) end end end
def initialize_dup(other) # :nodoc:
def initialize_dup(other) # :nodoc: super _clear_locking_column if locking_enabled? end
def locking_enabled? # :nodoc:
def locking_enabled? # :nodoc: self.class.locking_enabled? end