Everything There Is to Know About Associations in Rails

An **association** is a connection between two **Active Record models**. It makes much *easier* to perform various operations on the records in your code. I divided associations into four categories:

1. One to One
2. One to Many
3. Many to Many
4. Polymorphic One to Many

If you are new to Ruby on Rails, be sure to get up your [rails project](https://kolosek.com/ruby-programming-beginners-guide/) ready and check how to [create models](https://kolosek.com/rails-scaffold/) in Rails.

## One to One
When you set up **one-to-one** relations you are saying that a record contains exactly one instance of another model. For example, if each user in your application has only one profile, you can describe your models as: 

```
class User < ApplicationRecord       class Profile < ApplicationRecord
  has_one :profile                     belongs_to :user
end                                  end
```
One of the models in the given relation will have `has_one` method invocation and another one will have `belongs_to`. It is used to describe which model contains **a foreign key** reference to the other one, in your case, it is the profiles model. 

![one-to-one](https://storage.kraken.io/kk8yWPxzXVfBD3654oMN/dd9c653b0c0005b92cdf4a6bdcc10a3e/one-to-one.png)

Cover your associations with [RSpec tests](https://kolosek.com/rails-rspec-setup/) to make sure everything works the way you want it to.

## One to Many
A **one-to-many** association is the most common used relation. This association indicates that each instance of the model A can have **zero or more** instances of another model B and model B belongs to **only one** model A. 

Let's check it out via example. Let’s say you want to create an application where users can write multiple stories, your models should look like this:

```
class User < ApplicationRecord       class Story < ApplicationRecord
  has_many :stories                     belongs_to :user
end                                  end
```
Here, deciding which model will have `has_many` and which will have `belongs_to` is more important than in **one-to-one** relations, because it changes the logic of your application. In both cases, the second model contains one reference to the first model in form of a **foreign key**. 

*The second model doesn't know about the first model relation to it - it is not aware if the first model has a reference to more than one of them or just to one.*

![one-to-many](https://storage.kraken.io/kk8yWPxzXVfBD3654oMN/ec6c6326b0948276a487af75a13ee4c9/one-to-many.png)

The tests for associations get more complex to write the more relations you create. You should check it out how to create your own [association factories](https://kolosek.com/factory-girl-associations/) to make your testing life easier.

## Many to Many
**Many-to-many** associations are a bit more complex and can be handled in two ways, **"has and belongs to many"** and **"has many through"** relations.

### Has and Belongs to Many
A `has_and_belongs_to_many` association creates a direct **many-to-many** connection with another model. It is simpler than the other one, as it only requires calling `has_and_belongs_to_many` from both models.

![has-and-belongs-to-many](https://storage.kraken.io/kk8yWPxzXVfBD3654oMN/6e59bce7bc11d74d4f3b42aa264f0db8/has-and-belongs-to-many.png)

*Example:* Let's say, a user can have many different roles and the same role may contain many users, your models would be like this:

```
class User < ApplicationRecord       class Role < ApplicationRecord
  has_and_belongs_to_many :roles       has_and_belongs_to_many :users
end                                  end
```
You will need to create a **join table** for this association to work. It is a table that connects two different models. The join table is created with rails function `create_join_table :user, :role` in a separate [migration](https://kolosek.com/rake-db-commands/).

```
class CreateUserRoles < ActiveRecord::Migration
  def change
    create_table :user_roles, id: false do |t|
      t.references :user, index: true, foreign_key: true
      t.references :role, index: true, foreign_key: true
    end
  end
end
```
This is a very simple approach, but *you don't have the direct access to related objects*, you can only hold references to two models and nothing else.

### Has Many Through
Another way to define a **many-to-many** association is to use the **has many through** association type. Here you should define a **separate model**, to handle that connection between two different ones.

![has_many_through](https://storage.kraken.io/kk8yWPxzXVfBD3654oMN/78cbb30deb837728cb6d6153b31c6fb3/has_many_through.png)

Instead of putting down a new example, you should check [this one out](https://kolosek.com/rails-join-table/)! It explains everything you should know about this association.

Using the example of `has_and_belongs_to_many` association, this time the three models should be written like this:

```
class User < ApplicationRecord
  has_many :user_roles
  has_many :roles, through: :user_roles
end
 
class UserRoles < ApplicationRecord
  belongs_to :user
  belongs_to :role
end
 
class Role < ApplicationRecord
  has_many :user_roles
  has_many :users, through: :user_roles
end
```
This **association** will enable you to do things like `user.role` and to get a list of all connected second model instances. It will also enable you to get access to data specific to the relation between first and second models.

## Polymorphic
**Polymorphic associations** are the most advanced associations available to us. You can use it when you have a model that may belong to many different models on a single association.

![polymorphic](https://storage.kraken.io/kk8yWPxzXVfBD3654oMN/6058d06ae05bb5c5ea77ebbc9fa1aabf/polymorphic.png)

Let's imagine you want to be able to write comments for users and stories. You want both models to be commentable. Here's how this could be declared:

```
class Comment < ApplicationRecord
  belongs_to :commentable, polymorphic: true
end
 
class Employee < ApplicationRecord
  has_many :comment, as: :commentable
end
 
class Product < ApplicationRecord
  has_many :comment, as: :commentable
end
```
You can think of a polymorphic `belongs_to` declaration as **setting up an interface** that any other model can use. To declare the **polymorphic interface** you need to declare both a foreign key column and a type column in the model. You should [run the migration](https://kolosek.com/rake-db-commands/) once you are done.

```
class CreateComments < ActiveRecord::Migration
  def change
    create_table :comments do |t|
      t.text :body
      t.integer :commentable_id
      t.string :commentable_type
      t.timestamps
    end
 
    add_index :comments, :commentable_id
  end
end
```
This migration can be simplified by using **references**:

```
class CreateComments < ActiveRecord::Migration
  def change
    create_table :comments do |t|
      t.text :body
      t.references :commentable, polymorphic: true, index: true
      t.timestamps
    end
  end
end
```
## Aditional Options
There are a few additional options you can use when defining **relations between models**, I will cover two most commonly used ones.

### class_name
>*If the name of the other model cannot be derived from the association name, you can use the `:class_name` option to supply the model name. You can read more about this on [RailsGuides](http://guides.rubyonrails.org/association_basics.html#options-for-belongs-to-class-name).*
>

*Example:* You want the belongs_to relation to call for an **author**, but there are two problems: 
1. There is no model called in that way. 
1. The story table is missing an `author_id` field. 

*Easy fix!* To make this work and stop your [tests from failing](https://kolosek.com/rspec-controller-test/), you just have to specify the `:foreign_key` and the actual name of the class:

```
class Story < ApplicationRecord
  belongs_to :author, class_name: 'User', foreign_key: 'user_id'
end
```
### dependent
You can use this option when you want to get rid of **orphaned records** since they can lead to various problems. Orphaned records are created when you **delete or destroy** a model A that was associated with model B, but model B wasn't removed in the process.

```
class User < ApplicationRecord
  has_many :stories, dependent: :destroy
end
```
*Example:* Suppose, a user called Maria wrote a lot of stories. Then, you deleted Maria from the database, but the stories still have the user_id column set to Maria's id. These stories are called **orphaned records**.

Thank you for reading!

This article is originally published on [Kolosek Blog](https://kolosek.com/rails-associations/?utm_source=qi).