So, Rails4 added support for setting the transaction isolation level on transactions. Something Rails has needed sorely for a long time.
Unfortunately nowhere is it documented how to correctly detect if a Transaction has failed during your Transaction block (vs any other kind of error, such as constraints failures).
The right way seems to be:
RetryLimit = 5 # set appropriately…
txn_retry_count = 0
Model.transaction(isolation: :serializable) do
# do txn stuff here.
rescue ActiveRecord::StatementInvalid => err
txn_retry_count += 1
if txn_retry_count < RetryLimit
The transaction concurrency errors are all part of a specific family, which the current stable
pg gem correctly reproduces in it’s exception heirachy. However, ActiveRecord captures the exception and raises it as a statement error, forcing you to unwrap it one layer in your code.