← Back to Upcase

Multiple database in Rails


(João Daniel) #1

Is it possible for ActiveRecord and DatabaseCleaner to deal with two different databases during tests?

Some of my models are related to the Rails “default” database. Some other models are related to an external database which I do not manage. I have access to a Replica and all I do is read from it.

I was able to get this working using the establish_connection method from ActiveRecord, and providing a different connection for this model.

This worked fine on development and production environments. But I was having problems on the test environment.

For testing, I set up a no-data dump of the database and provided its connection to Rails.

module MultipleDatabasesExtension
    extend ActiveSupport::Concern

# add your static(class) methods here
module ClassMethods
    def establish_connection_to database_hash
        if Rails.env.test?
            establish_connection database_hash[:test]
        elsif Rails.env.development?
            establish_connection database_hash[:development]
        elsif Rails.env.production?
            establish_connection database_hash[:production]
        else
            establish_connection database_hash[:production]
        end
     end
  end
end

# include the extension 
ActiveRecord::Base.send(:include, MultipleDatabasesExtension)

After that I used

establish_connection_to({ 
  test: :replica_test,
  development: ENV['REPLICA_DATABASE_URL'],
  production: ENV['REPLICA_DATABASE_URL']
})
self.table_name = 'answers'

So it would select the correct database. I was trying to manage the database using:

db_config = ActiveRecord::Base.configurations["replica_test"]
ActiveRecord::Tasks::MySQLDatabaseTasks.new(db_config).structure_load("db/replica.sql")

So it would reload the database from the replica.sql file.

At this point, I can clean the database when by running the two commands above (I can make them a rake task). However I want to automate this by using DatabaseCleaner to correctly prepare the database for each test.

When I used the following excerpt:

RSpec.configure do |config|
  config.before(:suite) do
    DatabaseCleaner.clean_with(:deletion)
    DatabaseCleaner[:active_record,{:connection => :replica_test}].clean_with(:deletion)
  end

  config.before(:each) do
    DatabaseCleaner.strategy = :transaction
    DatabaseCleaner[:active_record,{:connection => :replica_test}].strategy = :transaction
  end

  config.before(:each, :js => true) do
    DatabaseCleaner.strategy = :deletion
    DatabaseCleaner[:active_record,{:connection => :replica_test}].strategy = :deletion
  end

  config.before(:each) do
    DatabaseCleaner.start
    DatabaseCleaner[:active_record,{:connection => :replica_test}].start
  end

  config.after(:each) do
    DatabaseCleaner.clean
    DatabaseCleaner[:active_record,{:connection => :replica_test}].clean
  end
end

and runned rake, it erased all my replica database on production!! What may happened? The connection clearly show a test database.

So, now I’m not sure what path to follow. Have you guys ever dealt with a multiple database like this? i.e., where one of them doesn’t live inside the app?

What’s the best strategy to configure it?