Rails Save a record within transaction even if transaction rolls back?

ruby-on-rails-3, transactions

Solution

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

Problem

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

Original source