Last active
December 24, 2025 15:11
-
-
Save ipvalverde/e442ccaf22657b2457ce50981c11a305 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # 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