Ruby Yagi šŸ

Ruby, Rails, Web dev articles

Automatically migrate database when pushing to Heroku

by Axel Kee 29 November 2020

Heroku makes deploying Ruby web app a breeze, however it doesnā€™t run rake db:migrate automatically each time you push a new commit to it.

You might have seen the error screen below after deploying your Rails app on Heroku:

error

I used to freak out when seeing this, but most of the time it is caused by me forgetting to run rake db:migrate after deploying a feature which has new database migrations.

If you view logs of the app, and see thereā€™s an error saying ā€˜relation ā€œtable_nameā€ does not existā€™ , it means the database migration is not run hence no table is created.

log saying table name does not exist

Wouldnā€™t it be good if thereā€™s a way to tell Heroku to automatically run ā€œrake db:migrateā€ after each git push? šŸ¤”

Heroku release phase

Luckily Heroku has a feature named ā€˜release phaseā€™, it allow us to run tasks after a git push is received, but before the app is deployed.

release phase

From Heroku documentation :

Release phase enables you to run certain tasks before a new release of your app is deployed. Release phase can be useful for tasks such as:

We can specify the commands to run during release phase in the Procfile file, using the release process type :

release: rake db:migrate
web: bundle exec puma -t 5:5 -p ${PORT:-3000} -e ${RACK_ENV:-development}

In the above Procfile , the ā€œrake db:migrateā€ command will be run during release phase.

If you want to run multiple rake commands in the release phase, you can put them together like this :

release: rake db:migrate other:thing whatever
web: bundle exec puma -t 5:5 -p ${PORT:-3000} -e ${RACK_ENV:-development}

(thanks for the tip Jonathan!)

Alternatively, you can put the commands into a single bash file (eg: release-tasks.sh, located at the root of your repository), then execute the bash file in the release phase like this :

release: ./release-tasks.sh
web: bundle exec puma -t 5:5 -p ${PORT:-3000} -e ${RACK_ENV:-development}

With this, you wonā€™t need to run migration task manually after each git push, and this can make continuous deployment simpler.