Writing Migrations for Polymorphic Associations in Ruby on Rails

When you want to create an association between a model and 2 or more other models, you need to create a polymorphic association.

Instead of a traditional association where an Image might belong to a Profile (shown below), a polymorphic association would allow images to belong to Profile, Blog Posts, and anything else that needs an image.

class Image < ApplicationRecord
  belongs_to :profile
end

class Profile < ApplicationRecord
  has_many :images
end

To make this reference polymorphic, just a few changes are needed:

class Image < ApplicationRecord
  belongs_to :imageable, polymorphic: true
end

class Profile < ApplicationRecord
  has_many :images, as: :imageable
end

We make the belongs_to call with a reference to :imageable since our Image will belong to multiple models. And instead of storing separate ids, like profile_id to point to profiles and blog_post_id to point to a blog post, we combine the ids into a shared id we call imageable_id.

To determine which table this id refers to, we also store a imageable_type that tells us the name of the model.


Writing Polymorphic Association Migrations

When we want to create a polymorphic table, we need to change a few things in our migrations.

Using the example above, our Image model can belong to either a Profile or a BlogPost. Instead of storing a profile_id or blog_post_id we store an id that can point to either called imageable_id. In order to determine which id the model points to we reference the imageable_type.

As illustrated above, we need 2 fields to make a polymorphic association:

  • id of the associated model
  • type of the model

Creating a Table With a Polymorphic Association

When we create a table we can either manually create these columns or use a shorthand helper method.

The manual approach would look like this and clearly lay out the columns we want:

class CreateImages < ActiveRecord::Migration[6.0]
  def change
    create_table :images do |t|
      t.bigint  :imageable_id
      t.string  :imageable_type
    end

    add_index :images, [:imageable_type, :imageable_id]
  end
end

Or we can use the shorthand references method. It doesn't explicitly show us all the columns being created but it's a little easier to work with.

class CreateImages < ActiveRecord::Migration[6.0]
  def change
    create_table :images do |t|
      t.references :imageable, polymorphic: true
    end
  end
end

Both approaches will result in the same change to your database.

Adding a Polymorphic Column to an Existing Table

You can use the add_reference method If you already created the table and just need to add a column,

Here's what it would look like:

class AddImageableToImages < ActiveRecord::Migration
  def change
    add_reference :images, :imageable, polymorphic: true, index: true
  end
end

This will do the same as all the other variants above, creating imageable_id and imageable_type fields.

Featured
Level up faster
One on Ones: 101
Leveraging Other People's Experience
Business ideas
Check out my list.
Hey, I'm Nicholas Dill.

I help people become better software developers with daily tips, tricks, and advice.

Level up
Related Articles
More like this
Polymorphic Associations in Ruby on Rails
How to Manage Null Constraints With Migrations in Ruby on Rails
How to Add Custom Filters to Administrate Dashboards