module TransactionTimestamps::Timestamp

Public Class Methods

included(base) click to toggle source
# File lib/transaction_timestamps/timestamp.rb, line 5
def self.included(base)
  base.class_eval do
    # override the original timestamp with one our own that returns transaction-based timestamps
    alias_method :original_current_time_from_proper_timezone, :current_time_from_proper_timezone
    def current_time_from_proper_timezone
      if use_transaction_timestamps?
        current_transaction_time
      else
        original_current_time_from_proper_timezone
      end
    end
  end
end

Public Instance Methods

current_time_from_proper_timezone() click to toggle source
# File lib/transaction_timestamps/timestamp.rb, line 9
def current_time_from_proper_timezone
  if use_transaction_timestamps?
    current_transaction_time
  else
    original_current_time_from_proper_timezone
  end
end
current_transaction_time() click to toggle source
# File lib/transaction_timestamps/timestamp.rb, line 19
def current_transaction_time
  if new_transaction?
    @@cached_timestamp = adjust_time_to_timezone(db_transaction_time)
  else
    @@cached_timestamp
  end
end

Private Instance Methods

adjust_time_to_timezone(time) click to toggle source
# File lib/transaction_timestamps/timestamp.rb, line 66
def adjust_time_to_timezone(time)
  # do exactly the same time adjustment as performed in ActiveRecord::Timestamp
  self.class.default_timezone == :utc ? time.utc : time.getlocal
end
db_transaction_time() click to toggle source
# File lib/transaction_timestamps/timestamp.rb, line 50
def db_transaction_time
  if postgresql?
    time_str = ActiveRecord::Base.connection.select_one("SELECT transaction_timestamp();")['transaction_timestamp']
    Time.parse(time_str)
  else
    # other databases (MySQL, sqlite) don't support retrieval of the actual transaction time, so the best we can
    # do is to use the current system time (and cache this until the transaction changes)
    Time.now
  end
end
new_transaction?() click to toggle source
# File lib/transaction_timestamps/timestamp.rb, line 35
def new_transaction?
  # check whether the transaction object id has changed since the last time we checked
  current_transaction_id = transaction_id
  is_new = !defined?(@@prev_transaction_id) || (current_transaction_id != @@prev_transaction_id)
  @@prev_transaction_id = current_transaction_id

  is_new
end
postgresql?() click to toggle source
# File lib/transaction_timestamps/timestamp.rb, line 61
def postgresql?
  defined?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter) &&
    ActiveRecord::Base.connection.instance_of?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
end
transaction_id() click to toggle source
# File lib/transaction_timestamps/timestamp.rb, line 44
def transaction_id
  # use the transaction object id as a unique identifier for whether the transaction has changed
  manager = ActiveRecord::Base.connection.instance_variable_get(:@transaction_manager)
  manager.current_transaction.object_id
end
use_transaction_timestamps?() click to toggle source
# File lib/transaction_timestamps/timestamp.rb, line 28
def use_transaction_timestamps?
  # Timecop doesn't play well transaction timestamps, so don't enable them when using Timecop
  # and the time is frozen
  TransactionTimestamps.enabled &&
    !(defined?(Timecop) && Timecop.frozen?)
end