figaro
figaro copied to clipboard
Undesired interaction between figaro/active_record for rake db tasks (rake runs twice for db tasks)
Not sure how to report this, but active record's (4.2.x) default behavior has some undesired side-effects on rake tasks when used with figaro. The rake db:* tasks run twice in the dev environment when RAILS_ENV is not set:
The following configuration:
application.yml
development:
MYSQL_DATABASE: rails_dev
MYSQL_USER: rails_dev
MYSQL_HOST: 127.0.0.1
...
test:
MYSQL_DATABASE: rails_test
MYSQL_USER: rails_test
MYSQL_HOST: 127.0.0.1
database.yml
development:
adapter: mysql2
database: <%= ENV['MYSQL_DATABASE'] %>
username: <%= ENV['MYSQL_USER'] %>
password: <%= ENV['MYSQL_PASSWORD'] %>
host: <%= ENV['MYSQL_HOST'] %>
test:
adapter: mysql2
database: <%= ENV['MYSQL_DATABASE'] %>
username: <%= ENV['MYSQL_USER'] %>
password: <%= ENV['MYSQL_PASSWORD'] %>
host: <%= ENV['MYSQL_HOST'] %>
results in rake tasks being run twice when RAILS_ENV is not specified:
(assuming one's db does not have rails_dev and rails_test defined)
$ bundle exec rake db:create --trace
** Invoke db:create (first_time)
** Invoke db:load_config (first_time)
** Execute db:load_config
** Execute db:create
rails_dev already exists
This is more obvious in the case when you are trying to drop the dbs:
$ bundle exec rake db:drop --trace
** Invoke db:drop (first_time)
** Invoke db:load_config (first_time)
** Execute db:load_config
** Execute db:drop
Database 'rails_dev' does not exist
$ bundle exec rake db:drop --trace
** Invoke db:drop (first_time)
** Invoke db:load_config (first_time)
** Execute db:load_config
** Execute db:drop
Database 'rails_dev' does not exist
Database 'rails_dev' does not exist
This behavior is caused by the active record lib/active_record/tasks/database_tasks.rb trying to be super-extra helpful and setting environments to an array containing both development and test, instead of leaving it alone:
def each_current_configuration(environment)
environments = [environment]
# add test environment only if no RAILS_ENV was specified.
environments << 'test' if environment == 'development' && ENV['RAILS_ENV'].nil?
Net result is that the rake tasks are run twice due on development environment when RAILS_ENV is not specified, due to how figaro is hooking into rails.
A workaround is to specify RAILS_ENV on the command line or in your environment, but what sane person would do that:
$ RAILS_ENV=development bundle exec rake db:create --trace
** Invoke db:create (first_time)
** Invoke db:load_config (first_time)
** Execute db:load_config
** Execute db:create
$ RAILS_ENV=development bundle exec rake db:drop --trace
** Invoke db:drop (first_time)
** Invoke db:load_config (first_time)
** Execute db:load_config
** Execute db:drop
So there you have it. I haven't looked into figaro's internals to figure out whether or not this is fixable.
Hopefully this report will save folks some time and hair from being pulled out in frustration.
It is not run twice. It is run once for each environment (dev & test).
But from database.yml
perspective all properties have the same values as where loaded into ENV
at the moment of application initialization with the exact environment in that exact moment (e.g. development
). In your example it drops rails_dev
for dev env and then drops rails_dev
for test env.
The problem is that figaro respects Twelve-Factor App, and Rails does not, it tries to be in two envs in a single run. Or does, in some way... Actually, if you set RAILS_ENV
the things become clear.
Actually, there should not be environments in the database.yml
when you're using figaro. Because "environmental" configs are defined by an explicit external set of environment variables. I'm hardly sure that Rails would like this.
Thanks for the explanation. So how do I solve this without having to run rake tasks like this each time?
RAILS_ENV=development bundle exec rake db:create
Same problem for me, and executing RAILS_ENV=development bundle exec rails db:create
also tries to create the db twice. @arantir @laserlemon have you any solution?
Having the same problem, any workaround?
I ended up just using the test environment. Rails itself tries to be too helpful and runs for both envs (always does the test one)