Skip to content

Instantly share code, notes, and snippets.

@pik
Created January 3, 2016 04:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pik/96442de2af444ee3cdb1 to your computer and use it in GitHub Desktop.
Save pik/96442de2af444ee3cdb1 to your computer and use it in GitHub Desktop.
Pessimistic Locking Concern for AR
module Lockable
extend ActiveSupport::Concern
LOCKABLE = { on: :self }
def transaction_has_lock_for(target)
(transaction_get_locks || []).include?(target)
end
def transaction_add_lock(lock)
locks = transaction_get_locks
if locks
locks << lock
else
ActiveRecord::Base.connection.current_transaction.instance_variable_set('@_locks'.freeze, [lock])
end
end
def transaction_get_locks
ActiveRecord::Base.connection.current_transaction.instance_variable_get('@_locks'.freeze)
end
def lock_target
if self.class::LOCKABLE[:on] == :self
self
else
current = self
if self.class::LOCKABLE[:through]
Array.wrap(self.class::LOCKABLE[:through]).each { |item| current = current.send(item) }
end
current.send(self.class::LOCKABLE[:on])
end
end
def acquire_pessimistic_lock!
# Note that lock! functions *will* clobber Dirty changes
unless transaction_has_lock_for(lock_target)
# _future_state = lock_target.changes.each_with_object({}) { |(key, val), h| h[key] = val[1]}
lock = lock_target.lock!
transaction_add_lock(lock)
# _future_state.each { |attr, value| lock.send(:write_attribute, attr, value) }
end
true
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment