Alter Table
This guide explains how to modify existing database tables using db-migrate
.
Basic Table Alterations
Use alter_table
to modify an existing table:
DB::Migrate.migrate("update_users_table", client) do
alter_table :users do
add_column :age, "INTEGER"
add_column :active, "BOOLEAN DEFAULT TRUE"
end
end
Adding Columns
Basic Column Addition
alter_table :users do
add_column :email, "TEXT"
add_column :phone, "TEXT"
end
Columns with Constraints
alter_table :users do
add_column :email, "TEXT NOT NULL"
add_column :age, "INTEGER", default: 0
add_column :status, "TEXT", unique: true
end
Dropping Columns
Basic Column Removal
alter_table :users do
drop_column :old_field
drop_column :deprecated_column
end
Safe Column Removal
Use if_exists
to avoid errors if the column doesn't exist:
alter_table :users do
drop_column :maybe_missing_column, if_exists: true
end
Renaming Columns
alter_table :users do
rename_column :full_name, :name
rename_column :email_address, :email
end
Changing Column Types
Use change_column
to modify a column's data type:
alter_table :users do
change_column :age, "INTEGER"
change_column :balance, "DECIMAL(10,2)"
end
Database-Specific Behavior
The gem automatically uses the appropriate syntax for your database:
PostgreSQL:
ALTER TABLE users ALTER COLUMN age TYPE INTEGER USING age::INTEGER;
MariaDB/MySQL:
ALTER TABLE users MODIFY COLUMN age INTEGER;
Multiple Operations
Combine multiple alterations in a single migration:
alter_table :users do
add_column :middle_name, "TEXT"
drop_column :old_field, if_exists: true
rename_column :full_name, :name
change_column :age, "INTEGER"
end
Advanced Examples
Data Type Conversions
# Convert text to integer with explicit casting
alter_table :products do
change_column :price_text, "DECIMAL(10,2)"
end
For PostgreSQL, this automatically includes a USING
clause for safe conversion.
Adding Columns with Complex Defaults
alter_table :orders do
add_column :order_number, "TEXT NOT NULL",
default: "'ORD-' || EXTRACT(epoch FROM NOW())::TEXT"
end
Conditional Schema Changes
alter_table :users do
# Only add column if it doesn't exist
unless information_schema.column_exists?(:users, :created_at)
add_column :created_at, "TIMESTAMP DEFAULT NOW()"
end
end
Feature Detection
The gem uses feature detection to ensure compatibility:
- Conditional Operations:
IF EXISTS
clauses are only used when supported - Column Modification: Uses
MODIFY COLUMN
(MariaDB) vsALTER COLUMN TYPE
(PostgreSQL) - Using Clauses: PostgreSQL's
USING
clause for safe type conversions
Best Practices
Safe Alterations
Always use conditional operations when uncertain:
alter_table :users do
drop_column :deprecated_field, if_exists: true
add_column :new_field, "TEXT"
end
Incremental Changes
Make small, focused changes rather than large alterations:
# Good: Focused change
alter_table :users do
add_column :email_verified, "BOOLEAN DEFAULT FALSE"
end
# Better than: Large, complex change
alter_table :users do
add_column :email_verified, "BOOLEAN DEFAULT FALSE"
add_column :phone_verified, "BOOLEAN DEFAULT FALSE"
add_column :two_factor_enabled, "BOOLEAN DEFAULT FALSE"
drop_column :old_verification_method, if_exists: true
rename_column :verification_code, :email_verification_code
end
Performance Considerations
For large tables, consider the performance impact of schema changes, especially when adding NOT NULL
columns without defaults.