module ActiveRecord::DelayTouching

Public Class Methods

apply() click to toggle source

Apply the touches that were delayed.

# File lib/activerecord/delay_touching.rb, line 62
def self.apply
  begin
    ActiveRecord::Base.transaction do
      state.records_by_attrs_and_class.each do |attr, classes_and_records|
        classes_and_records.each do |klass, records|
          touch_records attr, klass, records
        end
      end
    end
  end while state.more_records?
ensure
  state.clear_records
end
call() { || ... } click to toggle source

Start delaying all touches. When done, apply them. (Unless nested.)

# File lib/activerecord/delay_touching.rb, line 49
def self.call
  state.nesting += 1
  begin
    yield
  ensure
    apply if state.nesting == 1
  end
ensure
  # Decrement nesting even if `apply` raised an error.
  state.nesting -= 1
end
state() click to toggle source
# File lib/activerecord/delay_touching.rb, line 40
def self.state
  Thread.current[:delay_touching_state] ||= State.new
end
touch_records(attr, klass, records) click to toggle source

Touch the specified records–non-empty set of instances of the same class.

# File lib/activerecord/delay_touching.rb, line 77
def self.touch_records(attr, klass, records)
  attributes = records.first.send(:timestamp_attributes_for_update_in_model)
  attributes << attr if attr

  if attributes.present?
    current_time = records.first.send(:current_time_from_proper_timezone)
    changes = {}

    attributes.each do |column|
      column = column.to_s
      changes[column] = current_time
      records.each do |record|
        # Don't bother if destroyed or not-saved
        next unless record.persisted?
        record.instance_eval do
          write_attribute column, current_time
          @changed_attributes.except!(*changes.keys)
        end
      end
    end

    klass.unscoped.where(klass.primary_key => records).update_all(changes)
  end
  state.updated attr, records
  records.each { |record| record.run_callbacks(:touch) }
end

Public Instance Methods

touch(*names) click to toggle source

Override ActiveRecord::Base#touch.

Calls superclass method
# File lib/activerecord/delay_touching.rb, line 9
def touch(*names)
  if self.class.delay_touching? && !try(:no_touching?)
    DelayTouching.add_record(self, *names)
    true
  else
    super
  end
end