Zhu Wu's Blog

The world is a fine place and worth fighting for.

Rake DB Tasks Always Runs Twice in Development Environment

Recently, we set up a new Rails project (named as app below), and our database.yml is shown below, so you can see that it reads from environment variables to set database names and credentials accordingly:

default: &default
  adapter: postgresql
  encoding: unicode
  pool: <%= ENV['DATABASE_POOL'] %>
  host: <%= ENV['DATABASE_HOST'] %>
  database: <%= ENV['DATABASE_NAME'] %>
  username: <%= ENV['DATABASE_USER'] %>
  password: <%= ENV['DATABASE_PASSWORD'] %>

development:
  <<: *default

test:
  <<: *default

we noticed that rake DB tasks always run twice in development environment as shown below:

$ rake db:drop
Dropped database 'app_development'
Dropped database 'app_development'
$ rake db:create
Created database 'app_development'
app_development already exists

After I drill down the problem, I found that the problem is caused by a 'smart' feature in Rails. When running DB rake tasks, ActiveRecord checks the current environment, and if current environment is development, it runs the task in development database first and followed by test database (you can refer to method each_current_configuration in lib/activerecord/tasks/database_tasks.rb for more details).

Our database.yml relies on environment variables to determine the target database. When a rake DB task is executed in development environment, the task will be run upon development database first, which is app_development. Then, the task is run upon test database, which is app_development again, because the environment variables for databases are the same. That is why the same task is run twice on development database.

To fix this, I simply hard code the database name for test environment in database.yml:

test:
  <<: *default
  database: knight_test