diff options
Diffstat (limited to 'activerecord/lib')
-rwxr-xr-x | activerecord/lib/active_record/associations.rb | 11 | ||||
-rw-r--r-- | activerecord/lib/active_record/locking/optimistic.rb | 35 |
2 files changed, 44 insertions, 2 deletions
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index d94cc03938..6dbee9f4bf 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1500,7 +1500,16 @@ module ActiveRecord when :destroy method_name = "has_many_dependent_destroy_for_#{reflection.name}".to_sym define_method(method_name) do - send(reflection.name).each { |o| o.destroy } + send(reflection.name).each do |o| + # No point in executing the counter update since we're going to destroy the parent anyway + counter_method = ('belongs_to_counter_cache_before_destroy_for_' + self.class.name.downcase).to_sym + if(o.respond_to? counter_method) then + class << o + self + end.send(:define_method, counter_method, Proc.new {}) + end + o.destroy + end end before_destroy method_name when :delete_all diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb index 9044ca418b..60ad23f38c 100644 --- a/activerecord/lib/active_record/locking/optimistic.rb +++ b/activerecord/lib/active_record/locking/optimistic.rb @@ -23,6 +23,16 @@ module ActiveRecord # p2.first_name = "should fail" # p2.save # Raises a ActiveRecord::StaleObjectError # + # Optimistic locking will also check for stale data when objects are destroyed. Example: + # + # p1 = Person.find(1) + # p2 = Person.find(1) + # + # p1.first_name = "Michael" + # p1.save + # + # p2.destroy # 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. # @@ -39,6 +49,7 @@ module ActiveRecord self.lock_optimistically = true alias_method_chain :update, :lock + alias_method_chain :destroy, :lock alias_method_chain :attributes_from_column_definition, :lock class << self @@ -88,7 +99,7 @@ module ActiveRecord unless affected_rows == 1 - raise ActiveRecord::StaleObjectError, "Attempted to update a stale object" + raise ActiveRecord::StaleObjectError, "Attempted to update a stale object: #{self.class.name}" end affected_rows @@ -100,6 +111,28 @@ module ActiveRecord end end + def destroy_with_lock #:nodoc: + return destroy_without_lock unless locking_enabled? + + unless new_record? + lock_col = self.class.locking_column + previous_value = send(lock_col).to_i + + affected_rows = connection.delete( + "DELETE FROM #{self.class.quoted_table_name} " + + "WHERE #{connection.quote_column_name(self.class.primary_key)} = #{quoted_id} " + + "AND #{self.class.quoted_locking_column} = #{quote_value(previous_value)}", + "#{self.class.name} Destroy" + ) + + unless affected_rows == 1 + raise ActiveRecord::StaleObjectError, "Attempted to delete a stale object: #{self.class.name}" + end + end + + freeze + end + module ClassMethods DEFAULT_LOCKING_COLUMN = 'lock_version' |