Module: ActiveRecord::Locking::Optimistic
- Defined in:
- lib/active_record/locking/optimistic.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
. To override the name of the lock_version column, invoke the set_locking_column
method. This method uses the same syntax as set_table_name
Defined Under Namespace
Modules: ClassMethods
Class Method Summary collapse
-
.included(base) ⇒ Object
:nodoc:.
Instance Method Summary collapse
- #attributes_from_column_definition_with_lock ⇒ Object
-
#locking_enabled? ⇒ Boolean
:nodoc:.
-
#update_with_lock ⇒ Object
:nodoc:.
Class Method Details
.included(base) ⇒ Object
:nodoc:
25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/active_record/locking/optimistic.rb', line 25 def self.included(base) #:nodoc: super base.extend ClassMethods base.cattr_accessor :lock_optimistically, :instance_writer => false base.lock_optimistically = true base.alias_method_chain :update, :lock base.alias_method_chain :attributes_from_column_definition, :lock class << base alias_method :locking_column=, :set_locking_column end end |
Instance Method Details
#attributes_from_column_definition_with_lock ⇒ Object
44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/active_record/locking/optimistic.rb', line 44 def attributes_from_column_definition_with_lock result = attributes_from_column_definition_without_lock # If the locking column has no default value set, # start the lock version at zero. Note we can't use # locking_enabled? at this point as @attributes may # not have been initialized yet if lock_optimistically && result.include?(self.class.locking_column) result[self.class.locking_column] ||= 0 end return result end |
#locking_enabled? ⇒ Boolean
:nodoc:
40 41 42 |
# File 'lib/active_record/locking/optimistic.rb', line 40 def locking_enabled? #:nodoc: lock_optimistically && respond_to?(self.class.locking_column) end |
#update_with_lock ⇒ Object
:nodoc:
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/active_record/locking/optimistic.rb', line 59 def update_with_lock #:nodoc: return update_without_lock unless locking_enabled? lock_col = self.class.locking_column previous_value = send(lock_col) send(lock_col + '=', previous_value + 1) affected_rows = connection.update(<<-end_sql, "#{self.class.name} Update with optimistic locking") UPDATE #{self.class.table_name} SET #{quoted_comma_pair_list(connection, attributes_with_quotes(false))} WHERE #{self.class.primary_key} = #{quote_value(id)} AND #{self.class.quoted_locking_column} = #{quote_value(previous_value)} end_sql unless affected_rows == 1 raise ActiveRecord::StaleObjectError, "Attempted to update a stale object" end return true end |