How to comment Rails migrations

We recently learned how you could apply comments to your migrations in Rails

Thanks to David Bryant Copeland’s book, Sustainable Web Development with Ruby on Rails, we learned that you could add comments to your migrations in Rails. These will help document column names in the migration files, schema, and database.

When we talk about comments, we don’t just mean something like;

# creates a new table to store posts
def change
  create_table :posts do
   ...
  end
end

Using # creates a code comment. We mean something that gets executed and stored in the database.

The easiest way to show this is with an example.

We want to add basic blog posts to our site; we’ve decided the name we use is post, and they will have a unique title and a body that will contain the content of the blog post.

Here is our migration file;

class CreatePosts < ActiveRecord::Migration[6.0]
  def change
    create_table :posts, comment: 'Holds all the blog posts for the site' do |t|
      t.string :title, null: false, comment: 'The title of the blog post'
      t.text :body, null: false, comment: 'The main content of the blog post, will be paragraphs of text'
    end

    add_index :posts, :title, unique: true, comment: 'Title should be unique, or else it might confuse readers if two blog posts had the same name'
  end
end

In our create_table call, we add a comment which describes the table. For each attribute, we add a comment describing the attribute. Finally, for our index, we also add a comment.

The comments against the table and title are arguably overkill since it is repeating the name. I added them for completeness.

However, commenting on our “body” attribute helps people know there is lots of text going into it, not just a sentence or two. Likewise, with the index, we can add the reason it has a unique requirement.

When we run rails db:migrate, this will update the schema file, which will now look like this;

create_table "posts", comment: "Holds all the blog posts for the site", force: :cascade do |t|
  t.string "title", null: false, comment: "The title of the blog post"
  t.text "body", null: false, comment: "The main content of the blog post, will be paragraphs of text"
  t.index ["title"], name: "index_posts_on_title", unique: true, comment: "Title should be unique or else it might confuse readers if two blog posts had the same name"
end

You can hopefully already see the benefit here; as our schema grows, it will become helpful documentation for other developers, including the future you!

These comments also get added to the database itself. In the following examples, I’ve removed some information to make the formatting of the output a little easier on the eye.

This is the relevant output from calling \d+ once connected to your database in psql;

 Schema |  Name | Type  | Description
--------+----------------------+----------+----------+----------
 public | posts | table | Holds all the blog posts for the site

And if we pass in a table name, we see the column comments. \d+ posts;

 Column |       Type        | Description
--------+-------------------+-----------+----------+-----------------------------------+---
 id     | bigint            |
 title  | character varying | The title of the blog post
 body   | text              | The main content of the blog post, will be paragraphs of text
Indexes:
    "posts_pkey" PRIMARY KEY, btree (id)
    "index_posts_on_title" UNIQUE, btree (title)
Access method: heap

On a large enough project, you will have people interacting with your data in loads of weird and wonderful ways; having it documented at the source will help improve understanding for everyone, not just Rails developers.

This article is a part of the "Rails migrations" series


Recent posts View all

Ruby

Forcing a Rails database column to be not null

How you can force a table column to always have something in it with Rails

Writing Marketing

We've deleted an article's worth of unhelpful words

We've improved several pages across our site by removing words that add no value, and often detract from the article.