Search code examples
ruby-on-railsrakedatabase-schemarails-migrations

Reinitialize Rails development and test databases from the current working tree state


When you work with rails, and run say db:schema:dump or db:structure:dump from Rake it will write out the state of your development DB into the schema files. When we run the tests, db:test:prepare also copies the current state of the development database - which makes sense, to a degree, because you are probably working on a feature that needs database tweaks for the current branch.

However, we often need to reset the development database to the state that can be achieved by performing all the migrations in sequence, and then reset the testing database to conform to that - and then write out the schema/structure that can be committed to the source tree for the production branch. Currently, we do this with this monstrosity of a shell command:

bundle exec rake db:drop && bundle exec rake db:create && \
bundle exec rake log db:migrate > /tmp/miglog.log && \
bundle exec rake db:schema:dump && \
RAILS_ENV=test bundle exec rake db:drop && \
RAILS_ENV=test bundle exec rake db:create && bundle exec rake 
db:test:prepare

This looks horrible, is absolutely unreadable and also very slow because every invocation here boots the Rails env afresh.

Here's what I was wondering: could we remove some steps from this command? And could we fold these into a handwritten Rake task? I presume that would be difficult because the Rails environment gets configured differently depending on RAILS_ENV, but would love to at least remove the Rails env reloading.


Solution

  • You could simplify this to

    bundle exec rake db:migrate:reset 
    bundle exec rake db:test:prepare 
    

    The reset task runs drop, create, migrate. Running migrations dumps the schema anyway (unless you've changed dump_schema_after_migration to false)

    The test:prepare step as you know, dumps and loads the schema, and also does a purge (depends slightly on database adapter but basically drops and recreates the database). Given that you have already just dumped the schema, you could change this to

    bundle exec rake db:migrate:reset 
    bundle exec rake db:test:load_schema 
    

    Lastly, the tasks in db:test largely know that they should only run against the test database - regardless of rails env they use the test database when needed, so you could just do

    bundle exec rake db:migrate:reset db:test:load_schema 
    

    Lastly, there are some who would also tell you that running migrations from scratch is heresy and that the definitive source of truth is schema.rb (as generated by your production environment)