Problem: I'm looking for an ActiveRecord (Rails 3.2) callback hook that will execute BEFORE a DB transaction has begun.
If it doesn't exist (and I don't think it does), then I'm looking for any advice in monkey-patching ActiveRecord so that we can implement such a method ourselves.
What I've Tried
Having looked at ActiveRecord docs and playing around with the code, it seems that only 'after_commit' is guaranteed to be executed outside a transaction. Everything else ("before_validation", "before_save", "before_commit") is ran within the transaction. I've tried overriding the 'transaction' method:
class User < ActiveRecord::Base
included do |base|
base.instance_eval do
def before_transaction
### DO STUFF
end
def transaction(options = {}, &block)
before_transaction { super(options, &block) }
end
end
end
But this is complicated because transaction is a class method and the callback has to be registered per instance of the model. On top of that, it isn't guaranteed to run outside of a DB transaction because it could be nested:
ActiveRecord::Base.transaction do
ActiveRecord::Base.transaction do
user.update_attribute(name: "Hodor")
end
end
Not sure what I want is possible given the way ActiveRecord is implemented, because it may not be possible to know if another transaction has already begun and invoke the callback then. In any case, I thought it's worth asking here.
Background
I'm trying to 'sync' an existing Rails model (let's call it User) to a user service that lives elswhere. The user service should act as the source of truth.
Whenever updates happen to the Rails User model, I would like to validate + commit the change to the user service first, before saving to the DB (which only the Rails project use). The DB for the Rails project then functions as a write-through cache (why a Database for a cache? Legacy code reasons).
If we could call the service BEFORE writing to the DB, we don't have to worry about rolling back the transaction (and dealing with what happens when that rolling back fails!). However, I am hesitant to call the service in the middle of an open DB transaction, which is why I'm looking into whether or not it's possible to build a "before_transaction" callback.
Aucun commentaire:
Enregistrer un commentaire