Working more efficiently with rails migrations

I've been working on a major schema refactor on a rails application recently, and time and again I've had to reset my database because of some syntax error or another in my migrations. I'm changing schemas and moving data between columns, which makes the migrations really fragile.

It's also been fun learning about the rake tools that allow you to manage database migrations. In particular, three rails commands have come in handy:

rake db:migrate   #runs all migrations in order that aren't in the schema_migrations table
rake db:rollback  #rolls back one migration
rake -T -A        #shows you a list of what rake tasks you can actually run

It's been really annoying trying to figure out what rake commands there are and what they do, so the last command was a big breakthrough for me.

Often, if a migration fails, I want to roll back that migration. But the migration isn't recorded in the rails database yet. So I need some way to insert the migration into the database so I can then roll it back using rake. Other times, I want to delete the most recent migration from the database, so I can run it again without changing the state of the database. And finally, the third bash function I've written lets me run mysql or enter the shell without typing more than I need to:

I've developed a few bash aliases that have been invaluable in helping me roll back and roll forward single migrations, or enter the shell to investigate what's going on after a given migration:

# e.g. mudam db/migrate/20151101_my_migration.rb will add "20151101" to the end of the schema_migrations table.
mudam() {
  MIGRATION=$(echo ${1} | sed -e 's/[^0-9]//g')
  mysql -uroot database -e "INSERT INTO schema_migrations VALUES ('${MIGRATION}');"
}
muddm() {
  mysql -uroot database -e "DELETE FROM schema_migrations ORDER BY version DESC LIMIT 1;"
}
#connect to the database you care most about, optionally passing in a command entered without quotes
#e.g. mud select id, name from users limit 10
mud(){
  if [[ "$#" > 0 ]]; then
    mysql -uroot database -e "$*"
  else
    mysql -uroot database
  fi
}

Add new comment