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

Add db:prepare rake task. #35768

Merged
merged 6 commits into from Apr 2, 2019
Merged

Conversation

@robertomiranda
Copy link
Contributor

@robertomiranda robertomiranda commented Mar 27, 2019

In favor of getting merging #33139 (comment). I have implemented rake db:prepare which creates the database, loads the schema, run the migrations and initializes with the seed data
(use db:reset to also drop the database first). This rake task runs in an idempotent way

cc @davidstosik @matthewd @guilleiguaran

It Creates the database, loads the schema, run the migrations and initializes with the seed data
(use db:reset to also drop the database first). This rake task runs in an idempotent way

ref rails#33139 (comment)
@matthewd
Copy link
Member

@matthewd matthewd commented Mar 27, 2019

🙏🏻

This obviously isn't very mutli-DB aware, but it at least exposes an API that we'll be able to maintain when we fix that. 👌🏻 (@eileencodes may have stronger feelings on whether this can merge as is, or should grow that support first.)

I have similar feelings about the implementation tbh.. just connecting then rescuing NoDatabaseError feels a bit rough, but I don't have any immediate better suggestion. (Though I have vague recollection there are cases where we don't actually get that exception -- if we can't connect at all [because the DB we asked for isn't there], we may not be able to tell why.) One thought would be to move the migrate to an else after the rescue, to clarify that the exception is only expected to come from the connect.

We should add a couple of tests, covering the no DB, present-but-behind DB, and already-up-to-date DB cases -- but no need to get exhaustive: we can lean on the existing coverage of the underlying commands for details and edge cases.

@simi
Copy link
Contributor

@simi simi commented Mar 27, 2019

🤔 Doesn't this conflict with db:test:prepare? Let's say both prepare database to useful state, but both do that with different approach with different result. Is that ok? Isn't that a little confusing?

@robertomiranda
Copy link
Contributor Author

@robertomiranda robertomiranda commented Mar 27, 2019

thanks @matthewd @simi, for your prompt feedback.

This obviously isn't very mutli-DB aware, but it at least exposes an API that we'll be able to maintain when we fix that. 👌🏻 (@eileencodes may have stronger feelings on whether this can merge as is, or should grow that support first.)

Ideally, I was thinking to call something like ActiveRecord::Base.db_exists? but unfortunately at the moment seems like we don't have this API implemented yet. Looking forward to hearing a suggestion from @eileencodes 🙇

Doesn't this conflict with db:test:prepare? Let's say both prepare database to useful state, but both do that with different approach with different result. Is that ok? Isn't that a little confusing?

@simi good catch, I know this is a hard question 😅 but do you have any naming suggestion?

@eileencodes
Copy link
Member

@eileencodes eileencodes commented Mar 27, 2019

I looked at this and making it work for multiple db is pretty simple. We can looop through the configs, try to migrate and if we can't migrate run setup. I tested this on a local app by deleting one of the dbs in a multi-db app and not the others.

Also I recommend the name construct so we don't conflict with prepare.

New code would look like this:

  desc "Runs setup if database does not exist, or runs migrations if it does"
  task construct: :load_config do
    ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).each do |db_config|
      ActiveRecord::Base.establish_connection(db_config.config)

      begin
        db_namespace["migrate"].invoke
      rescue ActiveRecord::NoDatabaseError
        db_namespace["setup"].invoke
      end 
    end 
  end 

I think we can test this in the railties/test//application/rake/multi_dbs_test.rb for multiple databases and potentially also activerecord/test//cases/tasks/database_tasks_test.rb

@robertomiranda
Copy link
Contributor Author

@robertomiranda robertomiranda commented Mar 28, 2019

thanks much 🙇 @eileencodes, I gonna implement this suggestion and a couple of test cases on the files that you suggested

@matthewd
Copy link
Member

@matthewd matthewd commented Mar 28, 2019

Hmm... I like db:prepare because of the overlap with db:test:prepare: the latter is a specialized version of the general operation, which is "do what you must to get this into a state that I can use it".

I also think it's hard to find an alternative that works for both the create and migrate use cases: e.g. you can definitely construct a database into existence, but I'm not sure about constructing an old database to bring it up to date.

(I also also don't think giving this a different name fixes the potential for confusion with db:test:prepare: whatever it's called, they do nominally do the same thing but have different results. There's a real higher level ambiguity; it's not two very different operations with too-similar names, which can be fixed by moving them further apart.)

@guilleiguaran
Copy link
Member

@guilleiguaran guilleiguaran commented Apr 1, 2019

Agree with @matthewd, db:prepare sounds adequate in my opinion.

@rails-bot rails-bot bot added the railties label Apr 2, 2019
@robertomiranda robertomiranda force-pushed the r/rake-db-prepare branch 3 times, most recently from ede4850 to 6cefe76 Apr 2, 2019
@robertomiranda
Copy link
Contributor Author

@robertomiranda robertomiranda commented Apr 2, 2019

Hi, 👋 I've test cases for multiple and single DB connection, Also I tested locally with a couple of rails apps and it's looking good. Could you please take a look again?

Copy link
Member

@eileencodes eileencodes left a comment

This is looking good but I think we need one more test. Can you add one that drops the db first and then runs prepare and makes sure that create and migrate are both run?

@robertomiranda
Copy link
Contributor Author

@robertomiranda robertomiranda commented Apr 2, 2019

@eileencodes done 👍

@simi
Copy link
Contributor

@simi simi commented Apr 2, 2019

@matthewd @guilleiguaran I'm ok with db:prepare as well, just wanted to ensure db:test:prepare is "taken into account" as well when deciding the name.

simi
simi approved these changes Apr 2, 2019
@eileencodes eileencodes merged commit 2c4dab1 into rails:master Apr 2, 2019
3 checks passed
@eileencodes
Copy link
Member

@eileencodes eileencodes commented Apr 2, 2019

Thanks @robertomiranda!

@robertomiranda
Copy link
Contributor Author

@robertomiranda robertomiranda commented Apr 3, 2019

thanks a lot for all your help 🙇

@robertomiranda robertomiranda deleted the r/rake-db-prepare branch Apr 3, 2019
@robertomiranda
Copy link
Contributor Author

@robertomiranda robertomiranda commented Apr 3, 2019

oh actually, I have a question should we update the CHANGELOG?

@simi
Copy link
Contributor

@simi simi commented Apr 3, 2019

I think this change deserves changelog change. Feel free to open new PR @robertomiranda.

tahb added a commit to dxw/rails-template that referenced this issue Nov 15, 2019
* `rake db:prepare` looks to be equivalant. It runs the migration, if no database can be found it then seeks to create one. rails/rails#35768
* Given that this method is now tested as part of rails we have more confidence in the previous bug that reset the database despite it existing. Presumably this was caused by an error in how we were checking if a migration was pending so we should try removing our production guard.
tahb added a commit to dxw/rails-template that referenced this issue Nov 15, 2019
* `rake db:prepare` looks to be equivalant. It runs the migration, if no database can be found it then seeks to create one. rails/rails#35768
* Given that this method is now tested as part of rails we have more confidence in the previous bug that reset the database despite it existing. Presumably this was caused by an error in how we were checking if a migration was pending so we should try removing our production guard.
@albertvaka
Copy link

@albertvaka albertvaka commented Nov 22, 2019

If I understand correctly: this creates the DB if it doesn't exist, otherwise it runs migrations. Are you folks trying to abstract the fact that the database might not exist yet? It really seems like a dangerous idea: if you are running an app, you must know if you have a DB with data already or not. Once you know it, choosing one of two separate commands is trivial.

Furthermore, if you don't know the difference between these two different states (creating the DB for the first time vs running migrations on an existing database) this can feel unpredictable, magic-like and overall confusing.

tahb added a commit to dxw/rails-template that referenced this issue Jul 10, 2020
* `rake db:prepare` looks to be equivalant. It runs the migration, if no database can be found it then seeks to create one. rails/rails#35768
* Given that this method is now tested as part of rails we have more confidence in the previous bug that reset the database despite it existing. Presumably this was caused by an error in how we were checking if a migration was pending so we should try removing our production guard.
tahb added a commit to dxw/rails-template that referenced this issue Jul 10, 2020
* `rake db:prepare` looks to be equivalant. It runs the migration, if no database can be found it then seeks to create one. rails/rails#35768
* Given that this method is now tested as part of rails we have more confidence in the previous bug that reset the database despite it existing. Presumably this was caused by an error in how we were checking if a migration was pending so we should try removing our production guard.
tahb added a commit to dxw/rails-template that referenced this issue Jul 10, 2020
* `rake db:prepare` looks to be equivalant. It runs the migration, if no database can be found it then seeks to create one. rails/rails#35768
* Given that this method is now tested as part of rails we have more confidence in the previous bug that reset the database despite it existing. Presumably this was caused by an error in how we were checking if a migration was pending so we should try removing our production guard.
tahb added a commit to dxw/rails-template that referenced this issue Jul 24, 2020
* `rake db:prepare` looks to be equivalant. It runs the migration, if no database can be found it then seeks to create one. rails/rails#35768
* Given that this method is now tested as part of rails we have more confidence in the previous bug that reset the database despite it existing. Presumably this was caused by an error in how we were checking if a migration was pending so we should try removing our production guard.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

6 participants