Created
September 16, 2014 19:18
-
-
Save betamatt/27b9801fb7a2af00d3fc to your computer and use it in GitHub Desktop.
Deferred ActiveRecord touches
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# When using this, be careful about your testing transactions. | |
# ActiveRecord after_commit hooks don't play nice with transactional fixtures | |
# consider adding the test_after_commit gem to your test group | |
ActiveRecord::Base.class_eval do | |
DEFERRED_KEY = "deferred" | |
def touch_with_defer(name = nil) | |
raise ActiveRecordError, "cannot touch on a new record object" unless persisted? | |
defer_until_commit([self.class.name, id, name, "touch"].map(&:to_s).join(":")) { touch_without_defer(name) } | |
end | |
alias_method_chain :touch, :defer | |
private | |
def defer_until_commit(key, &block) | |
logger.debug "block deferred until commit with key #{key}" | |
if set = Thread.current[DEFERRED_KEY] ||= {} | |
logger.debug "skipping a duplicate deferral of key #{key}" if set[key].present? | |
set[key] ||= block | |
end | |
end | |
after_commit do | |
logger.debug "Flushing deferred queue" | |
while (set = Thread.current[DEFERRED_KEY]).present? | |
# Remove keys from the hash to be safely re-entrant | |
set.keys.each do |k| | |
logger.debug "undefer block with key #{k}" | |
set.delete(k).call | |
end | |
end | |
end | |
after_rollback do | |
Thread.current[DEFERRED_KEY] = nil | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment