Skip to content

Instantly share code, notes, and snippets.

@jeremy
Created February 11, 2015 18:26
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jeremy/84134ad08f2a137aa1ef to your computer and use it in GitHub Desktop.
Save jeremy/84134ad08f2a137aa1ef to your computer and use it in GitHub Desktop.
require 'active_support/concern'
module Touchless
module TouchLater
extend ActiveSupport::Concern
included do
# Preserve immediate touch behavior as touch_now
alias_method :touch, :touch_now
alias_method :touch_later, :touch
# TODO: only want this callback registered if touch was called,
# so untouched records needn't be tracked by the transaction.
before_commit :defer_touch_until_commit
end
# Defer touch until just before the db transaction commits. Rely on
# after_touch callbacks to fire and bubble touches (also deferred until
# transaction commit) up to parents.
def touch_later(*names)
raise ActiveRecordError, "cannot touch on a new record object" unless persisted?
# Mark the usual suspects plus the attrs requested for later touching
@_touch_attrs ||= timestamp_attributes_for_update_in_model
@_touch_attrs |= names
# Update this record's timestamps, but don't mark them as changed so
# this record doesn't get sucked in to a belongs_to autosave.
surreptiously_touch attrs
connection.add_transaction_record self
end
# Touch these attributes, but pretend like nothing changed so they don't
# get swept up and automatically saved when the associated record saves.
private def surreptiously_touch(attrs)
@_touch_time = current_time_from_proper_timezone
attrs.each { |attr| write_attribute attr, @_touch_time }
clear_attribute_changes attrs.keys
end
private def defer_touch_until_commit
if @_touch_attrs.present?
# TODO: accept an optional time: argument rather than always using
# the current time.
touch_now *@_touch_attrs, time: @_touch_time
end
end
end
end
# Wire up Active Record when it's available.
require 'activesupport/lazy_load_hooks'
ActiveSupport.on_load :active_record do
include ::Touchless::TouchLater
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment