Locking to prevent repeating transition

20 views
Skip to first unread message

Andrew Cove

unread,
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
end

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')
end

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)

p1.attempt
p2.attempt

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
Forward
0 new messages