Rails' Polymorphic Associations
Tags: rails, programming, tutorial
Published: 2018-07-14 11:00:27

---
title: Rails' Polymorphic Associations
published: true
description: 
tags: #rails #programming #tutorial
cover_image: 
---  

In this post I'll give you an overview of how polymorphic associations work in Rails and how to add them to your projects.  

## How I Got Here
I'm on my final lap at [Flatiron School](https://flatironschool.com/) now and completing my final project. If the last 4 cycles of project-building have taught me anything, it’s the importance of considering the data. *‘What sorts of models will be appropriate and how should they be associated in the database?’* 

To answer the first question, I wanted to build an application that would allow users to browse through upcoming events. I also wanted organizers to be able to log in and add to the listings. So, 2 models then: `Organizer` and `Event`. But both of these models need an `Address`, right? 3 models. But, how to associate them? This question led me right into unfamiliar territory: **polymorphic associations**.

## What's Polymorphism?
Working with Rails’ Active Record library up to that point I had encountered and come to understand most of the available [Active Record associations](http://guides.rubyonrails.org/association_basics.html): `belongs_to`, `has_many`, `has_many :through`, and so on. But in this instance, I needed a way to associate two different models with one model while keeping things DRY. Specifically, I needed a way to associate an Organizer and an Event with an Address that didn’t involve creating separate Address-like models for each.

A polymorphic association to the Address turned out to be the perfect tool for accomplishing this because as the [documentation](http://guides.rubyonrails.org/association_basics.html#polymorphic-associations) explains, with this type of association “a model can belong to more than one other model, on a single association”.

## Ok, but how do I implement this?
We can think of implementing a polymorphic association as creating an interface between the reusable model and the models that need to connect to it. The conventional way to name such interfaces is by adding an '-able' to the end of the model name so, addressable, commentable, imageable etc.

```ruby
class Address < ApplicationRecord
# name the interface to the Address model addressable
# establish that it is polymorphic
belongs_to :addressable, polymorphic: true
end

class Organizer < ApplicationRecord
# establish a relationship to the Address model 
# via the addressable interface
has_one :address, as: :addresssable
end

class Event < ApplicationRecord
# establish a relationship to the Address model
# via the addressable interface 
has_one :address, as: :addressable
end
```

I won't lie. When I saw that `belongs_to` line, my initial reaction was, 'Cool. So there's an `Addressable` class somewhere?'. Nope! That line names the interface on our polymorphic model. Once the relationship between the polymorphized model and it’s parent is created, it is possible to refer to the parent like this: `@address.addressable`. We'll also be able to use statements like `@organizer.address` and `@event.address`.

To make this work, you need to declare both a **foreign key column** and a **type column** in the model that will point to the parent model, `Organizer` or `Event`.
```ruby
class CreateAddresses < ActiveRecord::Migration[5.2]
  def change
    create_table :address do |t|
    t.string :line1
    t.string :line2
    t.string :city
    t.string :state
    t.string :zip
    t.integer :addressable_id
    t.integer :addressable_type
    t.timestamps
    end

    add_index :addresses, [:addressable_type, :addressable_id]
  end
end
```

This migration can be simplified by using the `t.references` form:

```ruby
class CreateAddresses < ActiveRecord::Migration[5.2]
  def change
    create_table :address do |t|
    t.string :line1
    t.string :line2
    t.string :city
    t.string :state
    t.string :zip
    t.references :addressable, polymorphic: true, index: true
    t.timestamps
    end
  end
end
```

The migration can be generated like this:
```bash
rails g migration create_addresses line1:string line2:string city:string state:string zip:string addressable_id:integer addressable_type:string
```

Or, like this:
```bash
rails g migration create_addresses line1:string line2:string city:string state:string zip:string addressable:references{polymorphic}
```

## Conclusion
Polymorphic associations allow one model to belong to many models while keeping code nice and DRY. This kind of association enables such relationships by creating a special interface on the polymorphic or reusable model that allows other models to interact with it. Not convinced this is the pattern for you? Check out this [post](https://robots.thoughtbot.com/whats-the-deal-with-rails-polymorphic-associations) by Jared Carroll where he guides readers through a more in-depth exploration of this approach.