I have recently been touching an app which uses schema.rb
instead of structure.sql
. I have realised that I have “unlearned” one important aspect of it - when I do feature dev in branches, my standard approach to “reset my database to be off-main” was to git checkout main -- db/structure.sql
, then rake db:reset
followed by db:migrate
. Since structure.sql
includes INSERTs for all the schema_migrations
table entries, it would unambiguously record which migrations did and did not run - so this workflow is pretty bulletproof. I was surprised to find out that these rows do not get captured in schema.rb
- so when I want to rebase a feature branch and rerun the migrations in it, I need to muck about with the migration filename (so that its VERSION changes) or the entries in schema_migrations. Is there some Rails command sequence I am missing to replicate the workflow which I have with structure.sql
? Because it’s super-handy honestly, and with schema.rb it becomes a drag. To compare:
- With
structure.sql
- to apply migration from my feature branch:git checkout main -- db/structure.sql; rake db:migrate
- With
schema.rb
- to apply migration from my feature branch:git stash ... && git checkout main && <some kind of db reset> && git checkout <feature branch> ....
With the implicit “migrated to version” with schema.rb, Rails assumes that if there is a migration file in place with version N and there is a schema.rb and the version in the schema is higher than the version N, the migration has been applied and is recorded in the schema. So if the migration is “backdated” (which can easily happen if a branch gets rebased onto newer main
, for instance) it will be silently skipped, yet recorded in schema_migrations
.
What is the rationale behind having explicit schema_migrations entries in structure.sql but using the assumed version in schema.rb?