Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

When I run ENV=development rake db:create I don't expect it to try and create the test db too #27299

Closed
ioquatix opened this issue Dec 7, 2016 · 70 comments

Comments

@ioquatix
Copy link
Contributor

ioquatix commented Dec 7, 2016

Steps to reproduce

According to the following code:

def each_current_configuration(environment)
environments = [environment]
environments << "test" if environment == "development"

When running something like this:

ENV=development rake db:create

It also tries to create test.

I think this is violating the principle of least surprise. At a cursory glance, this also applies to drop_current which might be even more surprising.

Expected behavior

Only development environment is created.

Actual behavior

It tries to create test database too.

System configuration

Latest.

@ioquatix
Copy link
Contributor Author

ioquatix commented Dec 7, 2016

Here is some example output:

% RACK_ENV=development rake db:create                                                                       
{"adapter"=>"mysql2", "database"=>"vmail_development", "strict"=>true}
Database 'vmail_development' already exists
Created database 'vmail_test'

An example of where this is a bit odd, is when test is an sqlite3 in-memory database. Therefore, get this output every time.

@ioquatix
Copy link
Contributor Author

ioquatix commented Dec 8, 2016

So, here is the odd behyavior from db:drop

export RACK_ENV=development
rake db:drop
{"adapter"=>"mysql2", "database"=>"vmail_development", "strict"=>true}
Dropped database 'vmail_development'
Dropped database 'vmail_test'

I don't think that's good behaviour.

@ioquatix
Copy link
Contributor Author

ioquatix commented Dec 8, 2016

In the same vein, I'd like to point out the following inconsistencies:

task :environment do
    # This must be a symbol... or establish_connection thinks it's a URL.
    DATABASE_ENV = :development

    ActiveRecord::Base.configurations = {
        # This key must be a string or it will not be matched by ActiveRecord:
        'development' => {
            'adapter' => 'sqlite3',
            # This key must be a string or rake tasks will fail (e.g. each_current_configuration fails):
            'database' => 'db/development.db'
        }
    }

    # Connect to database:
    unless ActiveRecord::Base.connected?
        ActiveRecord::Base.establish_connection(DATABASE_ENV)
    end
end

I'd be happy to take a look at these issues, but I'd need to know if the Rails core team consider these to be problems or not.

@ioquatix
Copy link
Contributor Author

ioquatix commented Dec 9, 2016

What's even more.. inconsistent.. is the fact that once you actually connect, all the keys are symbols:

> Account.connection_config
=> {:adapter=>"mysql2", :database=>"vmail_development", :mail_root=>"/tmp/mail_root"}

@nfedyashev
Copy link
Contributor

Looks like a violation of the least surprise principle to me as well. Experienced that issue many times

@ioquatix
Copy link
Contributor Author

Honestly, the db:* tasks seem like a bit of a mess. For all the above reasons.. and the way they tie into Rails by default, which breaks unless you override a magical set of variables on "module DatabaseTasks" which in the documentation is described as a class.

@ioquatix
Copy link
Contributor Author

What kind of feedback would you like?

@ioquatix
Copy link
Contributor Author

I've been hacking up a solution. Something like this:

				def each_current_configuration(environment)
					unless configuration = ActiveRecord::Base.configurations[environment]
						raise ArgumentError.new("Cannot find configuration for environment #{environment}")
					end
					
					if configuration['database'].blank?
						raise ArgumentError.new("Configuration for environment #{environment} doesn't specify database")
					end
					
					yield configuration
				end

@ioquatix
Copy link
Contributor Author

So, I've been working on a gem which fixes all these issues (and more). https://github.com/ioquatix/activerecord-migrations

I'm not really sure if this is a solution, it's more of a monkey patch. But it solves a lot of pain points for us w.r.t. deployment with active record, which to be honest leaves a lot to be desired.

@ioquatix
Copy link
Contributor Author

ioquatix commented Dec 12, 2016

Just to clarify another inconsistency:

ActiveRecord::Base.configurations = {
	'production' => Database::APP_PRODUCTION,
	'development' => Database::APP_DEVELOPMENT,
	'test' => Database::TEST,
}

DATABASE_ENV = :production

# Access key.. via string:
ActiveRecord::Base.configurations[DATABASE_ENV.to_s]

# Actually connect.. need to use symbol:
ActiveRecord::Base.establish_connection[DATABASE_ENV]

If you try to use symbols in configurations, it breaks in other ways. If you try to use a string in establish_connection it thinks it's a URL.

@jsenitza
Copy link

Just chiming in here... We have been troubleshooting this issue today as well. It seems to just disregard our RAILS_ENV and tries to create the test db as well as our development db. This causes issues in our case since we have completely different setups for development and test, so it errors and says it can't create the test db.

@ioquatix
Copy link
Contributor Author

@JCSHoosier take a look at https://github.com/ioquatix/activerecord-migrations it fixes those issues by monkey patch.

@jsenitza
Copy link

@ioquatix Yep, looking through it now! Thanks!

@stale
Copy link

stale bot commented Mar 27, 2017

This issue has been automatically marked as stale because it has not been commented on for at least three months.
The resources of the Rails team are limited, and so we are asking for your help.
If you can still reproduce this error on the 5-1-stable branch or on master, please reply with all of the information you have about it in order to keep the issue open.
Thank you for all your contributions.

@SGospodinov
Copy link
Contributor

SGospodinov commented Mar 30, 2017

This issue still can be occurred in rails 5.1.0.rc1

The ENV=development rails db:create execution produces the following result:
Created database 'db/development.sqlite3'
Created database 'db/test.sqlite3'

But it is more concerning that dropping the test database drops the development one as well.
ENV=test rails db:drop
Dropped database 'db/development.sqlite3'
Dropped database 'db/test.sqlite3'

Rails version: 5.1.0.rc1
Ruby version: 2.4.0

@stale stale bot removed the stale label Mar 30, 2017
@edwardmp
Copy link
Contributor

edwardmp commented Apr 15, 2017

Can someone from the Rails core team explain the rationale behind adding test to the environments array if ENV is development?(

def each_current_configuration(environment)
environments = [environment]
environments << "test" if environment == "development"
) ?

@rafaelfranca
Copy link
Member

rafaelfranca commented Apr 20, 2017

Yes. The reason is rails new foo; rails g scaffold user name; rails db:create db:migrate; rails test have to pass without having to rails db:test:create.

@rafaelfranca
Copy link
Member

See also 6ca9031

@ioquatix
Copy link
Contributor Author

Why wouldn't rails test just create the test database if required? Wouldn't that make more sense?

@rafaelfranca
Copy link
Member

At first look yes, but that would also require to other tests frameworks to be changed and in this case I prefer to play safer and keep the behavior that is being like this for years.

@ioquatix
Copy link
Contributor Author

How can we make this not break our staging/development environment which most certainly doesn't want a test database.

@rafaelfranca
Copy link
Member

Maybe implementing the alternative suggested https://github.com/rails/rails/pull/24201/files#r56104919 and applications overriding the task to do what they want.

@iqbalhasnan
Copy link

well, I guess I'm not the only one facing this 'issue'.

@josh-levinson
Copy link

josh-levinson commented Nov 19, 2019

It's pretty strange to me there is no way to override this behavior.

I understand the Rails Core team expects this behavior, and wants new users to hit the ground running with simple commands, etc. That's fine.

But we're using AWS' ParameterStore to manage our credentials, so every time we make an unnecessary, and unexpected query, it costs more money and creates more issues for us.

Even if we accept that this behavior is "expected," despite it being surprising, I still believe there should be a way to override this behavior with a switch or something.

@barrkel
Copy link

barrkel commented Jan 21, 2020

If we have different database connections for test vs development, it appears this new scheme doesn't work at all. Whatever login we use for test (using a ramdisk for speed) doesn't work for development (using persistent disk for large amounts of test data). And there's no easy workaround that I can see, apart from patching the source.

@pustomytnyk
Copy link
Contributor

this should be configurable.

@esteban8a
Copy link

I got bitten by this today as well... Wasted about 4 hours looking into this particular issue until I found this thread.

If you add up all the hours everyone has invested in this not so obvious behavior you might be impressed by the amount of money that is being wasted because of an ego.

Quick advise: Listen to your users.

@ioquatix
Copy link
Contributor Author

@rafaelfranca Do you think there is any way we can revisit the decision here?

@rafaelfranca
Copy link
Member

No. This is by design.

@rafaelfranca
Copy link
Member

But, I'm open to an environment variable to disable that if that is what people want.

@jsenitza
Copy link

I think that would definitely help. When I ran into this years ago it was such a pain due to how we had everything configured. @tinco 's suggestion above would help. This also should be documented as an expected behavior somewhere (with the flag to disable).

@cyclotron3k
Copy link

I would find this useful. At the moment, we are copying around dummy database config files in our CI/CD pipelines.

@ioquatix
Copy link
Contributor Author

ioquatix commented Apr 23, 2020

Maybe when DATABASE_ENV or RAILS_ENV is specified explicitly, it can be respected (a flag as it were). The default with no ENV specified, which implies development, can also include test.

How about that?

@jmks
Copy link
Contributor

jmks commented Apr 23, 2020

I came across this yesterday too.

@rafaelfranca I tried the environment variable approach you described: #39027

@simi
Copy link
Contributor

simi commented Apr 23, 2020

@JCSHoosier Actually this behaviour is well documented.

bin/rake -D db:create
rake db:create
    Creates the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:create:all to create all databases in the config). Without RAILS_ENV or when RAILS_ENV is development, it defaults to creating the development and test databases.

Anyway creating only specified database should be somehow supported. Adding ENV variables is not systematic solution. If we should to make this configurable, I think it should be added as config option for active record and you can tweak this config using ENV variable on your own the same we do for example for static files:

config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?

@simi
Copy link
Contributor

simi commented Apr 23, 2020

Maybe when DATABASE_ENV or RAILS_ENV is specified explicitly, it can be respected (a flag as it were). The default with no ENV specified, which implies development, can also include test.

How about that?

🤔 That will make environment having no RAILS_ENV set and RAILS_ENV set to development (which is default) different and that will be breaking and also inconsistent change.

@rafaelfranca
Copy link
Member

I don't want this to be configurable. I'm not against people using this, but I also don't want this becoming mainstream feature.

There are clearly some use cases like creating test database in paid machine where creating those databases are expensive but this is not something everyone needs.

For those applications an environment variable is enough.

@deivid-rodriguez
Copy link
Contributor

Would it be possible to get the best of both worlds?

Keep rails new foo; rails g scaffold user name; rails db:create db:migrate; rails test passing by default without having to rails db:test:create, but also respect RAILS_ENV if passed explicitly to rails db:create.

It might require some internal refactoring, but from an end user point of view, it should be possible, right?

@JohnDBR
Copy link

JohnDBR commented Nov 19, 2020

I came across this yesterday too.

@rafaelfranca I tried the environment variable approach you described: #39027

This will be available in the next rails release?

@aesyondu
Copy link

I was working on a rails 4 legacy app, and I got assigned to another project using rails 5. When I did my usual bin/rake db:drop and bin/rake db:create I was confused why it keeps including the test database, even when I specify RAILS_ENV=development. I thought I was going crazy!

@CODY-RAY
Copy link

If you landed here like me

#39027 has seem to fixed this with

SKIP_TEST_DATABASE=true or ENV["SKIP_TEST_DATABASE"]=true

@dersnek
Copy link

dersnek commented Nov 15, 2023

What if it's the opposite and you want to drop/create a test db without creating a development db? Is there a solution for that? #39027 doesn't solve that issue.

@skipkayhil
Copy link
Member

What if it's the opposite and you want to drop/create a test db without creating a development db? Is there a solution for that? #39027 doesn't solve that issue.

$ RAILS_ENV=test bin/rails db:drop
Dropped database 'storage/test.sqlite3'

$ RAILS_ENV=test bin/rails db:create
Created database 'storage/test.sqlite3'

This issue is about the implication that RAILS_ENV=development does both development and test, but RAILS_ENV=test already just does test.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests