Manipulating schema migrations through rails console

about 4 years ago.

Sometimes when you add a field in Model in your rails application. you run the migration and all go well. However, another day you mess up with your database directly and now your field is missing and your application can't start. If you run rake db:migrate it says that no migration is pending. Either you delete the database and start over again or you simply can force the migration to work using a query to the database.

How to

First let's check our migration status through rake db:migrate:staus :

➜  blog git:(master) rake db:migrate:status 
database: blog

 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20160727113335  Create friendly id slugs
   up     20160727113510  Create posts
   up     20160727223610  Devise create users
   up     20160729164741  Add view count to posts
   up     20160806103231  Add draft to posts

where does rails keep this migration??

If you check you're database (I'm using postgress here) you will find a schema_migrations table

blog=# \d schema_migrations 
    Table "public.schema_migrations"
 Column  |       Type        | Modifiers 
---------+-------------------+-----------
 version | character varying | not null
Indexes:
    "unique_schema_migrations" UNIQUE, btree (version)

if we select all records we will get our migrations versions the same as above with rake db:migrate:status (without any information about the migration)

blog=# select * from schema_migrations;
    version     
----------------
 20160727113335
 20160727113510
 20160727223610
 20160729164741
 20160806103231
(5 rows)

So those migration are up because the version number exist in this table. for example if we have a problem with the view_count we can delete the migration version associated with that field like this:

blog=# delete from schema_migrations where version = '20160729164741';

than if we run rake db:migrate:status

➜  blog git:(master) rake db:migrate:status 
database: blog

 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20160727113335  Create friendly id slugs
   up     20160727113510  Create posts
   up     20160727223610  Devise create users
   down   20160729164741  Add view count to posts
   up     20160806103231  Add draft to posts

than we can run rake db:migrate.

Using rails console to manipulate schema

Of course this is handy sometimes but you can mess up something doing this through the RDBMS. Rather you can use rails console with a model for the migration table (after all it's a model).

2.3.1 :001 > class SchemaMigration < ActiveRecord::Base; self.primary_key = :version; end
 => :version 
class SchemaMigration < ActiveRecord::Base; self.primary_key = :version; end


2.3.1 :002 > SchemaMigration.first
  SchemaMigration Load (2.1ms)  SELECT  "schema_migrations".* FROM "schema_migrations"  ORDER BY "schema_migrations"."version" ASC LIMIT 1
 => #<SchemaMigration version: "20160727113335"> 

This way you avoid using SQL directly.