Skip to content

Instantly share code, notes, and snippets.

@jakecraige
Last active May 9, 2019 21:07
Show Gist options
  • Save jakecraige/083e06d1527da2f9a654257778c5c82f to your computer and use it in GitHub Desktop.
Save jakecraige/083e06d1527da2f9a654257778c5c82f to your computer and use it in GitHub Desktop.
Sample test showcasing unexpected nested transaction handling in Rails
# frozen_string_literal: true
begin
require "bundler/inline"
rescue LoadError => e
$stderr.puts "Bundler version 1.10 or later is required. Please update your Bundler"
raise e
end
gemfile(true) do
source "https://rubygems.org"
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
gem "rails", github: "rails/rails"
gem "sqlite3"
end
require "active_record"
require "minitest/autorun"
require "logger"
# This connection will do for database-independent bug reports.
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
ActiveRecord::Base.logger = Logger.new(STDOUT)
ActiveRecord::Schema.define do
create_table :posts, force: true do |t|
t.string :title, null: false
end
end
# Uncomment this module to apply patch to test how it affects test results.
#
# module ActiveRecordPatch
# def transaction(requires_new: nil, isolation: nil, joinable: true)
# if !requires_new && current_transaction.joinable?
# if isolation
# raise ActiveRecord::TransactionIsolationError, "cannot set isolation when joining a transaction"
# end
# yield
# else
# transaction_manager.within_new_transaction(isolation: isolation, joinable: joinable) { yield }
# end
# rescue ActiveRecord::Rollback
# # NOTE: This is what was added to the original implementation
# raise if !requires_new && current_transaction.joinable?
# end
# end
# module ActiveRecord
# module ConnectionAdapters # :nodoc:
# class SQLite3Adapter
# prepend ActiveRecordPatch
# end
# end
# end
class Post < ActiveRecord::Base
end
class MyError < StandardError
end
class BugTest < Minitest::Test
def test_rollback_error
ActiveRecord::Base.transaction do
Post.create(title: 'first')
ActiveRecord::Base.transaction do
Post.create(title: 'second')
raise ActiveRecord::Rollback
end
Post.create(title: 'last')
end
assert_nil(Post.find_by(title: 'first'))
assert_nil(Post.find_by(title: 'second'))
assert_nil(Post.find_by(title: 'last'))
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment