Ruby on Rails - Migrations
Ruby on Rails - Migrations
Section titled “Ruby on Rails - Migrations”Rails Migrations are a way to manage your database schema changes over time. Instead of writing SQL DDL (Data Definition Language) directly, you define schema changes in Ruby using a Domain-Specific Language (DSL). This allows your schema changes to be database-agnostic (mostly) and version-controlled along with your application code.
Benefits of using migrations:
- Collaboration: If one developer makes a schema change, others can update their local databases by running
rails db:migrate. - Deployment: Simplifies updating the production database schema during deployments.
- Version Control: Schema changes are part of your codebase and tracked in version control (e.g., Git).
- Database Independence: Migrations abstract away many database-specific SQL syntaxes.
Common Migration Operations
Section titled “Common Migration Operations”create_table(name, options): Creates a new table.drop_table(name): Deletes a table.rename_table(old_name, new_name): Renames a table.add_column(table_name, column_name, type, options): Adds a new column to a table.rename_column(table_name, old_column_name, new_column_name): Renames an existing column.change_column(table_name, column_name, type, options): Changes the type or options of a column.remove_column(table_name, column_name, options): Removes a column.add_index(table_name, column_name_or_columns, options): Adds an index to one or more columns.remove_index(table_name, options_or_column_name): Removes an index.add_reference(table_name, ref_name, options)oradd_belongs_to: Adds a foreign key reference.t.timestamps: A helper withincreate_tableblock that addscreated_atandupdated_atcolumns.
Supported Data Types in Migrations:
- :string (for short text, e.g., titles)
- :text (for longer text, e.g., descriptions)
- :integer (for whole numbers)
- :bigint (for larger whole numbers)
- :float (for floating-point numbers)
- :decimal (for precise decimal numbers, often used for currency)
- :datetime (for date and time)
- :timestamp (similar to datetime)
- :date (for date only)
- :time (for time only)
- :binary (for binary data)
- :boolean (for true/false values)
Common Column Options: :limit, :precision, :scale (for decimals), :default, :null (boolean), :index (boolean or options hash).
Creating Migrations
Section titled “Creating Migrations”You can generate migration files using the rails generate migration command. Rails uses a timestamp in the filename to ensure migrations are run in order.
Example: Generating migrations for our books and subjects tables (if not already generated by rails g model):
$ bin/rails generate migration CreateBooks title:string price:decimal:10,2 subject_id:bigint:index description:text published_at:date$ bin/rails generate migration CreateSubjects name:string:uniqThis will create files like db/migrate/YYYYMMDDHHMMSS_create_books.rb and db/migrate/YYYYMMDDHHMMSS_create_subjects.rb.
If you use rails generate model Book title:string ..., the migration is created automatically. The example above shows how to create migrations standalone. Notice :index creates an index on subject_id, and :uniq creates a unique index on name for subjects.
Editing Migration Files
Section titled “Editing Migration Files”Let’s look at the content of a generated (or manually created) migration file. For CreateBooks:
class CreateBooks < ActiveRecord::Migration[7.0] # Use your current Rails version def change create_table :books do |t| t.string :title, null: false t.decimal :price, precision: 10, scale: 2 # t.references :subject, null: false, foreign_key: true # Preferred way for foreign keys t.bigint :subject_id # If not using t.references t.text :description t.date :published_at
t.timestamps # Adds created_at and updated_at columns end # Add index separately if not using t.references with index: true or if subject_id was manual add_index :books, :subject_id unless index_exists?(:books, :subject_id) add_index :books, :title # Example: adding an index on title endendFor CreateSubjects:
class CreateSubjects < ActiveRecord::Migration[7.0] def change create_table :subjects do |t| t.string :name, null: false
t.timestamps end add_index :subjects, :name, unique: true unless index_exists?(:subjects, :name, unique: true) endendActiveRecord::Migration[7.0]specifies the Rails version this migration was written for.- The
changemethod is used for migrations that Active Record knows how to reverse automatically (e.g.,create_tablecan be reversed bydrop_table). - For non-reversible changes, you’d define separate
up(to apply changes) anddown(to revert them) methods. t.timestampsis a helper that addscreated_atandupdated_atcolumns, which Active Record manages automatically.null: falsemakes a column required at the database level.t.references :subject, foreign_key: trueis a convenient way to add asubject_idcolumn, an index on it, and a foreign key constraint.
Important: Avoid putting data seeding (e.g., Subject.create(...)) inside migration files. Migrations are for schema changes. Data seeding should go in db/seeds.rb or custom Rake tasks.
Running Migrations
Section titled “Running Migrations”To apply pending migrations to your development database:
$ bin/rails db:migrateRails keeps track of which migrations have already been run in the schema_migrations table. This command will only run migrations that haven’t been run yet.
Other useful migration commands:
bin/rails db:rollback: Reverts the last migration.bin/rails db:rollback STEP=3: Reverts the last 3 migrations.bin/rails db:migrate:status: Shows the status of all migrations (up or down).bin/rails db:migrate VERSION=YYYYMMDDHHMMSS: Migrates up or down to a specific version.bin/rails db:schema:load: Loads the schema fromdb/schema.rbinto the current environment’s database (destructive, drops existing tables). Useful for setting up a new database quickly.bin/rails db:seed: Runs thedb/seeds.rbfile.
Running Migrations for Different Environments
Section titled “Running Migrations for Different Environments”To run migrations for a specific environment (e.g., production), set the RAILS_ENV variable:
$ RAILS_ENV=production bin/rails db:migrateWhat is Next?
Section titled “What is Next?”With your database schema defined and migrated, you can now focus on building the controllers and views that will allow users to interact with your application’s data.