Skip to content

Instantly share code, notes, and snippets.

@alexpchin
Last active April 21, 2021 15:01
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save alexpchin/abe7034e587b2dc760b9 to your computer and use it in GitHub Desktop.
Save alexpchin/abe7034e587b2dc760b9 to your computer and use it in GitHub Desktop.
Generating Migrations

Generating Migrations

Migrations are a feature of Active Record that allows you to evolve your database schema over time. Rather than write schema modifications in pure SQL, migrations allow you to use an easy Ruby DSL to describe changes to your tables.

Another way of thinking about them is like a kind of version control (like git) for your application's database - only not as cool as Git (because Git rules).

##Each database starts empty Every database starts empty. Adding information to a database can be described as a series of steps, one after another... Migrations allow developers to save the most important steps like creating tables or adding columns. Later you can rollback to before these changes if something goes wrong, although you might lose data if you do this!

##Active Record & Ruby DSL Instead of writing complicated SQL statements with things like left-joins, inner-joins and outer-joins... which even an experienced web developer might find a stuggle to understand, (especially when they didn't write the code), Rails uses something called a Ruby DSL (Domain Specific Language).

  • DSL is used to make manipulating an applications' database MUCH easier.

DSL allows us to manipulate Ruby objects rather having to SELECT by table and column. This is because a table is just a representation of the information stored about an object.

##Generating a new migration

rails generate migration MigrationName

You can call a migration anything you want! However, it is generally good practise to describe what you are changing in the database so that other people can easily tell what it does.

The format of a migration name is usually:

  • In UpperCamelCase
  • In the format AddXXXtoYYY
  • Where XXX is usually SINGULAR (as it is a column)
  • Where YYY is usually PLURALIZED (as it is a table)

Running this will create a blank migration file which will be timestamped, it will look like:

  • db/migrate/20100207214725_addXXXtoYYY.rb

And will be in the db > migrate folder.

##When does a migration auto-populate? This is something that I found confusing when I was first learning about migrations. This only happens when:

The migration name is of the form "AddXXXToYYY" or "RemoveXXXFromYYY" AND is followed by a list of column names and types

For example:

rails generate migration AddPartNumberToProducts part_number:string

A migration containing the appropriate add_column and remove_column statements will automatically be created.

All other times, a blank migration will be created.

##Executing a migration Once you have a migration file that has been created. You need to run:

rake db:migrate

This will execute the migration files. It will execute them in the order of the earliest timestamp first, so the oldest one first.

##Editing a migration file

Within a migration file you need to include:

  • Instructions on what to do when you execute the migration
  • Instructions on what to do if you want to reverse/rollback a migration

Sometimes these instructions can be in the form of one change method:

class AddPartNumberToProducts < ActiveRecord::Migration
	def change
	end
end

And sometimes these instructions can be in the form of an up method AND a down method:

class ExampleMigration < ActiveRecord::Migration
	def up
	end

	def down
	end
end

##Change vs up/down? What is the difference?

###Change Method The change method is the normal way of writing migrations. It works for the majority of cases, where Active Record knows how to reverse the migration automatically.


An example: For many operations rails can guess what is the inverse operation (without problems). For example, in your case what is the reverse operation of add_column to call when you rollback? Of course it's remove_column. What is the inverse of create_table? It's drop_table. So in these cases rails know how to rollback and define a down method is superfluous


Currently, the change method supports only these migration definitions:

  • add_column
  • add_index
  • add_reference
  • add_timestamps
  • create_table
  • create_join_table
  • drop_table (must supply a block)
  • drop_join_table (must supply a block)
  • remove_timestamps
  • rename_column
  • rename_index
  • remove_reference
  • rename_table

###Up / down methods

This is usually used when Active Record does not know how to reverse a migration.


An example: for some kind of operation you still need to define the down method, for example if you change the precision of a decimal column how to guess the original precision on rollback? It's not possible, so you need to define the down method.


###Up The up method should describe the transformation you'd like to make to your schema.

###Down The down method of your migration should revert the transformations done by the up method.

If you did an up followed by a down - the table should be unchanged.

#####What to do when the migration is irreversible?

If your migration is irreversible, you should raise ActiveRecord::IrreversibleMigration from your down method.


An example: There are certain commands like remove_column that cannot be automatically reversed. This is because the information required to re-create the column is not available in the remove_column command, e.g. What datatype do you want the removed column to have? If Rails encounters such commands while reversing a migration, an ActiveRecord::IrreversibleMigration exception will need be raised.


I will do another blog on actually what to add inside the change & up/down methods.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment