The best kittens, technology, and video games blog in the world.

Tuesday, April 19, 2016

Automatically managing db/schema.rb

peering thru the bed rails watching coco play by damselfly58 from flickr (CC-NC-ND)
I've been living in schemaless NoSQL wonderland for quite a while, but I'm currently working on some mysql-based Rails applications, and managing db/schema.rb is a massive pain.

It's an automatically generated file, and such conventionally don't go into version control, but it also literally says "It's strongly recommended that you check this file into your version control system" in it. I'm still not completely convinced it's the right thing to do, but let's assume we follow the recommendations.

The problem is that you're probably not starting a fresh database for every branch - or carefully rolling back to master schema before you switch - you'll be switching branches a lot, and migrations will be applied in a different order than what they'd end up on master - so whenever you generate db/schema.rb you'll need to look at it manually to figure out what should be committed and what shouldn't. It's a very error prone process for something as frequent as writing migrations.

You could drop your database and recreate it from migrations every now and then, but you probably have some data you'd rather keep there.

Fortunately there's a solution! Oh, you can't just switch your team to a schemaless database? Well, in such case use this script:

Script regenerate_schema_rb:
#!/usr/bin/env ruby

require "fileutils"
require "pathname"

fake_database_yml = Pathname(__dir__) + "database.yml"
real_database_yml = Pathname("config/database.yml")

unless real_database_yml.exist?
  STDERR.puts "It doesn't seem like you're in a Rails application"
  exit 1

unless `git status` =~ /nothing to commit, working directory clean/
  STDERR.puts "Do not run this script unless git status says clean"
  exit 1

system "echo 'DROP DATABASE IF EXISTS schema_db_regeneration' | mysql -uroot"
system "echo 'CREATE DATABASE schema_db_regeneration' | mysql -uroot"

FileUtils.cp fake_database_yml, real_database_yml

system "rake db:migrate"
system "git checkout #{real_database_yml}"

Fake database.yml:

  adapter: mysql2
  encoding: utf8
  database: schema_db_regeneration
  pool: 5
  username: root

What it does is very straightforward - it keeps your existing database, and simply repoints database.yml at a fake one, and runs all the migrations against it. No manual edits necessary, and your next_tumblr_development database is safe.

No comments: