Understanding Active Record Migrations


com/understanding-active-record-migrations/Understanding Active Record MigrationsAndy LeverenzBlockedUnblockFollowFollowingFeb 22Originally published at web-crunch.

com on February 22, 2019.

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.

Subscribe to my channel or newsletter for automatic updatesWhat 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.


The syntax of a migration might look similar to the following:class CreatePosts < ActiveRecord::Migration[5.

2] def change create_table :posts do |t| t.

string :title t.

text :content t.

timestamps end endendOnce 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:$ rails g model Post title:string content:textNotice 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:$ rails db:rollbackYou can rest assure, removing those tables, columns, etc.

will happen smoothly.

Creating Active Record migrationsImagine 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.

$ rails generate migration AddSkuNumberToProducts sku_number:stringHere, 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 columnWhen 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 timesaverThe migration above generates the following:class AddSkuNumberToProducts < ActiveRecord::Migration[5.

2] def change add_column :products, :sku_number, :string endendBecause 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 variantsWant to add an index to that last migration?$ rails generate migration AddSkuNumberToProducts sku_number:string:indexIt’s as simple as passing :index at the end of the column you are making changes to.

That looks like this in the end:class AddSkuNumberToProducts < ActiveRecord::Migration[5.

2] def change add_column :products, :sku_number, :string add_index :products, :sku_number endendMore advanced greatness$ 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:class AddDetailsToProducts < ActiveRecord::Migration[5.

2] def change add_column :products, :price, :decimal, precision: 5, scale: 2 add_reference :products, :supplier, polymorphic: true endendType ModifiersOn 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.


on the date the migration is applied).

index Adds an index for the column.

Up and Down instead of ChangeIf 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:class CreateProducts < ActiveRecord::Migration[5.

2] def change create_table :posts do |t| t.

string :title t.

text :content t.

timestamps end endendYou see something like: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 endendBoth 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.

$ rails generate migration RemoveSkuNumberFromProducts sku_number:stringThis would create a new file in db/migrateclass RemoveSkuNumberFromProducts < ActiveRecord::Migration[5.

2] def change remove_column :products, :sku_number, :string endendThis is easier to rollback and allows you to pivot your app if the need ever arises.

Invoking relationshipsWouldn’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 Usermodel set up.

)$ rails generate migration AddUserRefToProducts user:referencesThe user:references line allows you to automatically create a user_id column with the appropriate index all in one command.

class AddUserRefToProducts < ActiveRecord::Migration[5.

2] def change add_reference :products, :user, foreign_key: true endendRelated contentUnderstanding Ruby on Rails ActiveRecord ValidationsDebugging Ruby on RailsUnderstanding the Ruby on Rails CLIShameless Plug!If you liked this post, I have more videos on YouTube and here on my blog.

Want more content like this in your inbox?.Subscribe to my newsletter and get it automatically.

Be sure to check out my course as well☝ Want to learn Ruby on Rails from the ground up?.Check out my upcoming course called Hello Rails.

Originally published at web-crunch.

com on February 22, 2019.

.. More details

Leave a Reply