Skip to content

Accidental replacement of main DB model connections in multi-database env #97

Description

@kaorukobo

Note: I will make a pull request that follows this issue.

Summary

When we use DatabaseCleaner for a multi-database environment, the connection for "main" models (i.e., models inheriting the connection pool from ActiveRecord::Base) gets replaced with the connection for non-main models.

Reproduction

For the full reproduction code, see https://gist.github.com/kaorukobo/8dd0e5ef6c8662cc5de88aceea5043a1

setcwd_to_tmpdir
load_gems
create_config_database_yml
setup_activerecord

# defines Foo model, which use the connection pool from ApplicationRecord.
def define_foo_model
  eval(<<~RUBY, TOPLEVEL_BINDING)
    class Foo < ApplicationRecord
      connection.exec_query "CREATE TABLE foos (id INTEGER PRIMARY KEY)"
      reset_column_information
    end
  RUBY
end

# defines Bar model, which connects to alternate DB to be cleaned by DatabaseCleaner.
def define_bar_model
  eval(<<~RUBY, TOPLEVEL_BINDING)
    class Bar < ApplicationRecord
      establish_connection :bar
      connection.exec_query "CREATE TABLE bars (id INTEGER PRIMARY KEY)"
      reset_column_information
    end
  RUBY
end

RSpec.describe do
  it "works" do
    define_foo_model

    expect(Foo.connection.tables).to eq(["foos"])

    cleaner = DatabaseCleaner::Cleaners.new
    cleaner[:active_record, :db => :bar].strategy = :truncation
    cleaner.clean

    # define Bar model after `cleaner.clean`
    define_bar_model

    # Foo.connection gets replaced with Bar's connection!
    #
    # expected: ["foos"]
    #      got: ["bars"]
    expect(Foo.connection.tables).to eq(["foos"])
  end
end

Activity

  1. BoutPure commented on Sep 23, 2024

    @BoutPure

    Got this error too. After specifying cleaners for primary (AR::Base) and then to secondary (some other model) DB I got AR::Base connection to wrong DB

    Quick workaround is to specify cleaning strategy for primary DB to be the last:

        DatabaseCleaner[:active_record, db: :secondary].strategy = :transaction
        DatabaseCleaner[:active_record, db: :primary].strategy = :transaction

    This will return primary DB connection to ActiveRecord::Base

  2. psparrow commented on Nov 22, 2024

    @psparrow

    Any update on this? @BoutPure's suggestion above does not solve the problem for me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions