Skip to content

Instantly share code, notes, and snippets.

@ipvalverde
Last active December 24, 2025 15:11
Show Gist options
  • Select an option

  • Save ipvalverde/e442ccaf22657b2457ce50981c11a305 to your computer and use it in GitHub Desktop.

Select an option

Save ipvalverde/e442ccaf22657b2457ce50981c11a305 to your computer and use it in GitHub Desktop.
# frozen_string_literal: true
require "bundler/inline"
gemfile(true) do
source "https://rubygems.org"
# Use Rails directly from GitHub (main branch - nightly/edge)
gem "rails", github: "rails/rails", branch: "main"
gem "sqlite3"
end
require "active_record/railtie"
require "minitest/autorun"
ENV["DATABASE_URL"] = "sqlite3::memory:"
class TestApp < Rails::Application
config.load_defaults Rails::VERSION::STRING.to_f
config.eager_load = false
config.logger = Logger.new($stdout)
config.secret_key_base = "secret_key_base"
end
Rails.application.initialize!
ActiveRecord::Schema.define do
create_table :users, force: true do |t|
t.string :name
t.boolean :active, default: true
t.timestamps
end
create_table :emails, force: true do |t|
t.string :email_address
t.integer :user_id
t.boolean :active, default: true
t.timestamps
end
end
class Email < ActiveRecord::Base
belongs_to :user, optional: true
validates :email_address, uniqueness: true
end
class User < ActiveRecord::Base
has_one :email
after_create :create_email_for_user
private
def create_email_for_user
email = build_email(email_address: "#{name}@example.com")
unless email.save
errors.add(:base, email.errors.full_messages.first || "Email creation failed")
raise ActiveRecord::Rollback
end
end
end
class NoopRollbackInNestedTransactionTest < ActiveSupport::TestCase
include ActiveRecord::TestFixtures
self.use_transactional_tests = false
setup do
User.destroy_all
Email.destroy_all
end
test "rollback in nested transaction is a no-op" do
user = User.create(name: "john")
user.save!
assert_equal true, user.active
assert_equal true, user.email.active
User.transaction do
user.active = false
Email.transaction do
email = user.email
email.active = false
email.save
raise ActiveRecord::Rollback
end
end
user.reload
# Both are committed to the database even though an ActiveRecord::Rollback was raised
assert_equal true, user.active, "Expect that the whole transaction fails and the user is not saved"
assert_equal true, user.email.active, "Expect that the email is not updated"
end
test "rollback in after_create callback is a no-op when nested in a transaction" do
Email.create!(email_address: "john@example.com")
user = User.new(name: "john")
saved = User.transaction do
# This will attempt to create an email with `john@example.com` which already exists
# and raise an ActiveRecord::RecordInvalid error
user.save
end
# This is probably returning `nil` because the nested transaction was rolled back
refute saved, "User should not be saved since create_email_for_user raised an ActiveRecord::Rollback error"
user.reload
refute user.persisted?, "User should not be persisted since create_email_for_user raised an ActiveRecord::Rollback error"
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment