figaro icon indicating copy to clipboard operation
figaro copied to clipboard

Undesired interaction between figaro/active_record for rake db tasks (rake runs twice for db tasks)

Open posiczko opened this issue 8 years ago • 5 comments

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.

posiczko avatar Dec 03 '15 16:12 posiczko

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.

hesalx avatar Jan 11 '16 01:01 hesalx

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

augustosamame avatar Aug 24 '16 17:08 augustosamame

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?

pedroadame avatar May 24 '17 11:05 pedroadame

Having the same problem, any workaround?

ingolfured avatar May 30 '18 08:05 ingolfured

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)

ingolfured avatar Jun 01 '18 10:06 ingolfured