1. Never modify the up of a committed migration
Editing the up of a committed migration invites chaos in your deploys and team sync.
# db/migrate/20230101120000_example_migration.rb
class ExampleMigration < ActiveRecord::Migration[6.0]
def up
add_column :users, :email, :string, null: false
end
def down
remove_column :users, :email
end
end
Once it is committed, leave up alone, or you force teammates into error-prone database version syncs. Write a new migration instead.
2. No application code in a migration
Ever joined a team where a migration would not run because of some error in a model?
Calling model classes or other Ruby inside a migration creates migrations that break later, as the code around them changes.
In plain terms:
- Day 1: you add
Post.create(title: "Migration Best Practices")in your migration. - Day 2: another dev adds
validates :content, presence: trueto the Post model. - Day 3: a new hire cannot run your day-1 migration, because of that validation.
What now, edit a committed migration?
The fix: run raw SQL. No ORM in migrations.
# db/migrate/20230101121000_add_jobs_count_to_user.rb
class AddJobsCountToUser < ActiveRecord::Migration[6.0]
def up
add_column :users, :jobs_count, :integer, default: 0
# Poor approach: depend on the User model which might change
# Good approach: use pure SQL for reliability
execute <<-SQL
UPDATE users
SET jobs_count = (SELECT count(*) FROM jobs WHERE jobs.user_id = users.id)
SQL
end
def down
remove_column :users, :jobs_count
end
end
SQL keeps the migration decoupled from your evolving business logic.
3. Always provide a down
Every migration should be undoable. If a change truly cannot be reversed, raise an exception so it is explicit.
# db/migrate/20230101121500_create_users.rb
class CreateUsers < ActiveRecord::Migration[6.0]
def up
create_table :users do |t|
t.string :name
t.timestamps
end
end
def down
drop_table :users
end
end
Sometimes you cannot afford to invest time in a down method. That is fine,
raise an error and tell your team before merging. Once it is committed, editing
a migration is hard and risky.