ActiveRecord and Migrations
Migrations in Rails can be fragile when using models; to avoid headaches, please use SQL
statements and avoid writing to your models in any way. As soon as you add in
something like User.save
, you’re bound to run into issues running migrations
from scratch later on.
Prepared statements allow us to safely insert or update our data, and we can be confident that the state of the database will be compatible with the SQL you are executing.
| class DoubleUserBalance < ActiveRecord::Migration
def up
# Double user's balance
prepared = ActiveRecord::Base.connection.raw_connection.prepare("
UPDATE users
SET balance = balance * ?
")
prepared.execute(2)
prepared.close
end
def down
# Halve user's balance
prepared = ActiveRecord::Base.connection.raw_connection.prepare("
UPDATE users
SET balance = balance * ?
")
prepared.execute(1/2)
prepared.close
end
end
|
This may at first seem a bit paranoid, as you can always use rake db:setup
to
load the database directly from schema.rb
. However, this will most likely bite
you when you least expect it - for example, if you deploy code to your staging
server daily, but to your production server weekly; you will eventually find that
migrations which worked when run individually, spontaneously combust when run as
a group. This can be caused by table column information not being reloaded
between migrations (forcing you to add in User.reset_column_information
when
you discover that it’s broken!).
Reverse (down) migrations are also essential to create and test. You never know when you might need to hastily rollback that prematurely deployed release.