Understanding Active Record Migrations
Tags: rails, ruby, activerecord, tutorial
Published: 2019-02-26 18:49:39

---
title: Understanding Active Record Migrations
published: true
tags: rails, ruby, activerecord, tutorial
canonical_url: https://web-crunch.com/understanding-active-record-migrations/
cover_image: https://thepracticaldev.s3.amazonaws.com/i/dtbr4h63m1fod8a4km6q.jpg
---

Active Record migrations (within Ruby on Rails) are a convenient way to alter your database schema of a period of time. This overview/guide is a look at just what you can achieve with migrations and why they are the backbone of any given Ruby on Rails application. We’ll talk about conventions, techniques, and how to extend a migration to fit your application’s own respective needs.

{% youtube WJxvcvKgiT8 %}

### What are migrations?

Active Record migrations use a Ruby DSL (Domain specific language) to generate the necessary SQL automatically so you don’t have to author it by hand. This allows you to keep your schema changes to be database independent.

Think of each migration as a new version of the database. You can add to the schema or subtract from the schema.

To view the schema is a Ruby on Rails application head to `db/schema.rb`.

The syntax of a migration might look similar to the following:

```ruby
class CreatePosts < ActiveRecord::Migration[5.2]
  def change
    create_table :posts do |t|
      t.string :title
      t.text :content

      t.timestamps
    end
  end
end

```

Once migrated a new database table called `posts` will be created. Inside the table will be a `title` column with the type `string`, a `column` column with the type `text`, and two `timestamp` columns called `created_at` and `updated_at` which you get for free with the `t.timestamps` line.

Creating this happens automatically with a `migration` of which you can generate from the command line. In most cases the “creation” of a table happens when you create a new model within rails.

That might look like this:

```bash
$ rails g model Post title:string content:text

```

Notice the conventions at play here. The model name in this generation needs to be singular but translates down to plural. So while the command states `Post`. A new migration file within `db/migrate` will contain a `posts`.

The `change` method allows the migration to “change”. So in the event, you need to roll back your database:

```bash
$ rails db:rollback

```

You can rest assure, removing those tables, columns, etc.. will happen smoothly.

### Creating Active Record migrations

Imagine you’re building a new feature to your Ruby on Rails application and you need a new column on a table you’ve already generated by creating a new model within the rails CLI.

To create a new migration you can call to it from the command line much like other generators.

```bash
$ rails generate migration AddSkuNumberToProducts sku_number:string

```

Here, it’s assumed I already have a `Product` model/table created. To extend the table I want to add a new column for a `sku` number to keep track of it internally.

There’s some awesomeness happening here that I love:

- The migration internals will know that if you add “Add” or “Remove” to the beginning of what you name your migration it will automatically generate the necessary Ruby DSL code to add or remove a column
- When a migration is born, the file gets timestamped and saved to `db/migrate`. There you can reference it as well as see the history of the migrations for the app.
- On the command line, you can optionally pass “columns” and their “type” to save some time. There are cases where it’s easier to write these by hand after creating the migration. Simply leave out any columns names to do this and head to the file that gets generated to make changes. You can declare however many you want.
- Pro tip. If you need a column with a type of `string`. On the command line, you can optionally omit the `:string` declaration of the column name you pass. The default is this type which can be a timesaver 

The migration above generates the following:

```ruby
class AddSkuNumberToProducts < ActiveRecord::Migration[5.2]
  def change
    add_column :products, :sku_number, :string
  end
end

```

Because of the migration naming conventions, the migration generated the correct change to implore on the `products` table in the database. This kind of magic helps keep you out of the weeds of SQL which is a huge perk of migrations.

#### Helpful variants

Want to add an index to that last migration?

```bash
$ rails generate migration AddSkuNumberToProducts sku_number:string:index

```

It’s as simple as passing `:index` at the end of the column you are making changes to.

That looks like this in the end:

```ruby
class AddSkuNumberToProducts < ActiveRecord::Migration[5.2]
  def change
    add_column :products, :sku_number, :string
    add_index :products, :sku_number
  end
end

```

### More advanced greatness

```bash
$ rails generate migration AddDetailsToProducts 'price:decimal{5,2}' supplier:references{poloymorphic}

```

You can do a lot with one bash command to generate a pretty unique migration. This generates the following:

```ruby
class AddDetailsToProducts < ActiveRecord::Migration[5.2]
  def change
    add_column :products, :price, :decimal, precision: 5, scale: 2
    add_reference :products, :supplier, polymorphic: true
  end
end

```

#### Type Modifiers

On top of columns and tables, you can pass modifiers through on a given migration. These might depend on certain scenarios and many will need to be added manually instead of from the command line. From the rails documentation, we get this list.

- `limit` Sets the maximum size of the `string/text/binary/integer` fields.
- `precision` Defines the precision for the `decimal` fields, representing the total number of digits in the number.
- `scale` Defines the scale for the `decimal` fields, representing the number of digits after the decimal point.
- `polymorphic` Adds a `type` column for `belongs_to` associations.
- `null` Allows or disallows `NULL` values in the column.
- `default` Allows setting a default value on the column. Note that if you are using a dynamic value (such as a date), the default will only be calculated the first time (i.e. on the date the migration is applied).
- `index` Adds an index for the column.

##### Up and Down instead of Change

If you’ve seen older tutorials and/or Rails apps/gems in the wild you might notice a different syntax within each migration file.

Instead of:

```ruby
class CreateProducts < ActiveRecord::Migration[5.2]
  def change
    create_table :posts do |t|
      t.string :title
      t.text :content

      t.timestamps
    end
  end
end

```

You see something like:

```ruby
class CreateProducts < ActiveRecord::Migration[5.2]
  def up
    create_table :posts do |t|
     t.string :title
     t.text :content

     t.timestamps
    end
  end

  def down
    remove_table :posts do |t|
     t.string :title
     t.text :content

     t.timestamps
    end
  end
end

```

Both work equally well, though the `change` method seems DRY-er no? When in doubt, use it.

Instead of using the `UP` or `DOWN` methods I would suggest creating another migration to perform a new change to the database schema.

#### A better approach?

Imagine you wanted to remove the `sku_number` entry from before. You could make a new migration for that.

```bash
$ rails generate migration RemoveSkuNumberFromProducts sku_number:string

```

This would create a new file in `db/migrate`

```ruby
class RemoveSkuNumberFromProducts < ActiveRecord::Migration[5.2]
  def change
    remove_column :products, :sku_number, :string
  end
end

```

This is easier to rollback and allows you to pivot your app if the need ever arises.

### Invoking relationships

Wouldn’t it be nice to get relationships defined automatically? In many applications, you need to relate models by adding a `modelname_id` to another table. This can be done with migrations but you can also speed up that process if you already know what direction you’re heading.

Imagine you have a `Product` model that you want to associate it with a given user. (It’s assumed you already have a `User`model set up.)

```bash
$ rails generate migration AddUserRefToProducts user:references

```

The `user:references` line allows you to automatically create a `user_id` column with the appropriate index all in one command.

```ruby
class AddUserRefToProducts < ActiveRecord::Migration[5.2]
  def change
    add_reference :products, :user, foreign_key: true
  end
end

```

### Related content

- [Understanding Ruby on Rails ActiveRecord Validations](https://dev.to/justalever/understanding-ruby-on-rails-activerecord-validations-11hj-temp-slug-6531874)
- [Debugging Ruby on Rails](https://dev.to/justalever/debugging-ruby-on-rails-55jk)
- [Understanding the Ruby on Rails CLI](https://web-crunch.com/understanding-the-ruby-on-rails-cli/)

### Shameless Plug!

If you liked this post, I have more videos on [YouTube](https://youtube.com/c/webcrunch) and here on my [blog](https://web-crunch.com). Want more content like this in your inbox? [Subscribe to my newsletter](https://web-crunch.com/subcribe) and get it automatically.

#### Check out my course
[![https://i2.wp.com/i.imgur.com/KIaaJEB.jpg?ssl=1](https://i2.wp.com/i.imgur.com/KIaaJEB.jpg?ssl=1)  
](https://hellorails.io)

![☝](https://s.w.org/images/core/emoji/11/72x72/261d.png) Want to learn Ruby on Rails from the ground up? Check out my upcoming course called [Hello Rails](https://hellorails.io).

The post [Understanding Active Record Migrations](https://web-crunch.com/understanding-active-record-migrations/) appeared first on [Web-Crunch](https://web-crunch.com).