I have a series of records to save as part of a transaction. In addition to normal AR records, I am doing a credit card gateway transaction. If it or the AR transactions fail, I want everything rolled back ... except for the data of the failed transaction (reason, date, etc.) that I get back from the credit card gateway. Something like
def pay
Payment.transaction do
payment.save
other.save
result = credit_card.purchase # this does the gateway transaction, no database stuff
if result.failure
raise ActiveRecord::Rollback
result.save # this is the part I want to always save
end
another.save
end
end
Is there a way to exclude a specific part within a transaction from rollback on failure?
Rails 3.2.5, MySQL 5.1
I'm not 100% sure I understand why you want to do this but could you just save the credit card stuff outside of your transaction?
result = nil
Payment.transaction do
payment.save
other.save
result = credit_card.purchase # this does the gateway transaction, no database stuff
if result.failure
raise ActiveRecord::Rollback
end
end
result.save
(you need to set result to nil before the transaction because of how block variable scoping works)
Another possible strategy is to use the fact that transactions are done a per connection basis. Two threads will use different connections, so you could do:
Payment.transaction do
payment.save
other.save
result = Thread.new do
ActiveRecord::Base.connection_pool.with_connection do
credit_card.purchase.tap do |result|
result.save
end
end
end.join.value
if result.failure
raise ActiveRecord::Rollback
end
end
or maybe just:
Payment.transaction do
payment.save
other.save
result = credit_card.purchase
Thread.new do
ActiveRecord::Base.connection_pool.with_connection do
result.save
end
end.join
if result.failure
raise ActiveRecord::Rollback
end
end
Here the purchase happens on another thread, i.e. with its own database connection. Anything that happens in that thread won't be rolled back
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With