Module: ActiveRecord::Locking
- Defined in:
- lib/active_record/locking.rb
Overview
Active Records support optimistic locking if the field lock_version
is present. Each update to the record increments the lock_version column and the locking facilities ensure that records instantiated twice will let the last one saved raise a StaleObjectError if the first was also updated. Example:
p1 = Person.find(1)
p2 = Person.find(1)
p1.first_name = "Michael"
p1.save
p2.first_name = "should fail"
p2.save # Raises a ActiveRecord::StaleObjectError
You’re then responsible for dealing with the conflict by rescuing the exception and either rolling back, merging, or otherwise apply the business logic needed to resolve the conflict.
You must ensure that your database schema defaults the lock_version column to 0.
This behavior can be turned off by setting ActiveRecord::Base.lock_optimistically = false
.
Class Method Summary collapse
-
.append_features(base) ⇒ Object
:nodoc:.
Instance Method Summary collapse
-
#update_with_lock ⇒ Object
:nodoc:.
Class Method Details
.append_features(base) ⇒ Object
:nodoc:
22 23 24 25 26 27 28 |
# File 'lib/active_record/locking.rb', line 22 def self.append_features(base) #:nodoc: super base.class_eval do alias_method :update_without_lock, :update alias_method :update, :update_with_lock end end |
Instance Method Details
#update_with_lock ⇒ Object
:nodoc:
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/active_record/locking.rb', line 30 def update_with_lock #:nodoc: if locking_enabled? previous_value = self.lock_version self.lock_version = previous_value + 1 affected_rows = connection.update( "UPDATE #{self.class.table_name} "+ "SET #{quoted_comma_pair_list(connection, attributes_with_quotes(false))} " + "WHERE #{self.class.primary_key} = #{quote(id)} AND lock_version = #{quote(previous_value)}", "#{self.class.name} Update with optimistic locking" ) raise(ActiveRecord::StaleObjectError, "Attempted to update a stale object") unless affected_rows == 1 else update_without_lock end end |