Rails and RSpec with Two Databases

June 18th, 2015

Maintaining Rails applications in the real world is not always straight-forward.

Recently I needed to enable a Rails 4.0.13 application which used a MySQL database as it’s default to also use a PostgreSQL database. Being a good TDD citizen, I also needed to ensure that the new tests would run in our CI environment.

Whilst I did find a helpful post, it didn’t tell me everything I needed to know. So I thought I’d share what I did.

Database Configuration

First of all, I configured environments for the PostgreSQL database within config/database.yml as follows:

# in addition to existing contents
postgres: &postgresql_defaults
  adapter: postgresql
  pool: 10
  timeout: 60000
  host: localhost
  template: template0

  database: foo_development
  <<: *postgresql_defaults

  database: foo_test
  <<: *postgresql_defaults

  database: foo_staging
  <<: *postgresql_defaults

  database: foo_production
  <<: *postgresql_defaults

Establish Connection in Model Class

In my case, I only needed to use one model class backed by a table from the extra database. Let’s imaginatively call this class Bar. So the class would be defined like this:

class Bar < ActiveRecord::Base
  establish_connection "#{Rails.env}_foo"

# the rest of the class

Note that you probably want to introduce an abstract class which establishes the connection if you have more than one model class which needs it.

Augment rake db tasks

So far so good. The next step was to ensure that the CI script on Buildkite handled the extra database. As you would expect, the script prepares to run the tests by dropping, creating and loading the schema of the database. To do this it uses some code common to all our builds, which includes running bundle exec rake db:drop and bundle exec rake db:create db:schema:load.

I wanted to find a way for the setup of the extra database to piggy-back on these rake tasks and, in so doing, use the existing script unchanged. I discovered I could do so by using the Rake::Task#enhance method. This allowed the rake db tasks to be augmented as follows:

namespace :db do
  task drop_foo: :environment do

  task create_foo: :environment do

  namespace :structure do
    task load_foo: :environment do
      if File.exist?(foo_structure_filename)
        ActiveRecord::Tasks::DatabaseTasks.structure_load(foo_db_config, foo_structure_filename)

def foo_structure_filename

def foo_db_config

def default_db_config

def reset_connection_to_mysql_db

Rake::Task['db:drop'].enhance do

Rake::Task['db:create'].enhance do

Rake::Task['db:schema:load'].enhance do

There are a couple of things I should explain here.

Let’s assume FooApp is the name of application which has foo as it’s default database. FooApp uses SQL rather than Ruby to define it’s schema so I copied db/foo_structure.sql from db/structure.sql in FooApp.

Also worthy of close attention is the call to the reset_connection_to_mysql_db method after the create_foo task. Without this, rake db:schema:load will load the default MySQL schema into the PostgreSQL database!


So there you have it. How to add an extra database to your Rails application and not break CI in the process. Discovering how to use the Rake::Task#enhance method to facilitate this was my main motivation for sharing this.

I hope it helps someone else.


Hi Keith, I have resolved the problem. `ActiveRecord::Tasks` is in Rails 4. Previously, I was in Rails 3. Thanks.

Posted by: zc 4 months later

Hi zc,

It’s difficult to help without a bit more context. If you can create a gist showing the command you ran and the output, I may be able to help.


Posted by: Keith Pitty 4 months later

I am getting `NameError: uninitialized constant ActiveRecord::Tasks` when using `ActiveRecord::Tasks::DatabaseTasks`. Could you help? Thanks.

Posted by: zc 4 months later

Comments are closed for this post.

Other posts

Previous post: Bundler and Disk Space

More recently: Effective Collaboration using GitHub PRs

© 2020 Keith Pitty, all rights reserved.