Locking to prevent repeating transition

Skip to first unread message

Andrew Cove

Nov 25, 2012, 12:44:07 AM11/25/12
to pluginaw...@googlegroups.com
I'm using state_machine with ActiveRecord. I want to make sure that I can't charge a payment more than once. So:

event :attempt do
  transition :unprocessed => :attempted

after_transition :unprocessed => :attempted, :do => :charge!

And since I want to prevent multiple payments, I lock the record before transactions (using postgres)

before_transition do |payment, transition|
      payment.lock!('FOR UPDATE')

the call to #lock! reloads the record. 

If I then get two instances of the payment and attempt them

p1 = Payment.find(1)
p2 = Payment.find(1)


The problem is that it's too late: even though payment.state will be "processed" after the first charge, and lock! will reload it (so p2 will have the right state), but the transition will think it's from unprocessed to processed, and charge again.

Is there a way to kill the transition in the callback if payment.state != transition.from? Is there a better way to ensure that a stale instance of a record can't do a no-longer-valid transition?

Reply all
Reply to author
0 new messages