Ruby & Active Record Associations
Tags: ruby, rails, tutorial
Published: 2022-10-03 16:52:08

In this guide you will learn: 

- How to declare associations between models using Active Record
- How to understand the different types of associations available with Active Record
- How to use the methods automatically added to your models after creating these associations

Using associations with Active Record is very powerful and an important part of using Ruby with databases. An **association** is a connection between two Active Record **models**. These associations provide built-in methods to make your databases easier to work with. This walkthrough assumes that you already understand how to create migrations and models. 

There are 6 types of associations:
- `belongs_to`
- `has_one`
- `has_many`
- `has_many :through`
- `has_one :through`
- `has_and_belongs_to_many`

To figure out which type of association that fits your needs, it is helpful to create an ** Entity Relationship Diagram (ERD)**. There are helpful tools online to create your own ERD quickly and easily, but you can also use pen and paper! 

- [Lucidchart](https://www.lucidchart.com/pages/examples/er-diagram-tool)
- [Smartdraw](https://www.smartdraw.com/entity-relationship-diagram/er-diagram-tool.htm)
- [dbdiagram.io](https://dbdiagram.io/home)

For this walkthrough, we will use dbdiagram.io. 

---

##belongs_to, has_many

![belongs to association](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q05zy10epg8pfp04edww.png)

The `belongs_to` association sets up a connection between two models, where the instance of one model "belongs to" the second model. In this example we have one author who has written many books. In this case, each book `belongs_to` an author. This association is made through the **foreign key**. 

> Note: From [Flatiron School docs](https://learn.co/lessons/activerecord-associations-review) - "Foreign keys are columns that refer to the primary key of another table. Conventionally, foreign keys in Active Record are comprised of the name of the model you're referencing, and _id. So for example if the foreign key was for a posts table it would be post_id." Read more about foreign keys at [The Odin Project](https://www.theodinproject.com/lessons/ruby-on-rails-active-record-associations).

Here is the corresponding code: 

```javascript
class Book < ActiveRecord::Base
  belongs_to :author
end
```

Note that the `belongs_to` association must use the singular term ("author"). From the [official docs](https://guides.rubyonrails.org/association_basics.html): "This is because Rails automatically infers the class name from the association name. If the association name is wrongly pluralized, then the inferred class will be wrongly pluralized too."

The other side of the coin for this particular example, the author's `has_many` relationship, would look like this: 

```javascript
  class Author < ActiveRecord::Base
    has_many :books
  end
```
---

##belongs_to, has_one

If we changed our example above so that each author _only_ wrote a single book, we could use the `has_one` association: 

```javascript
  class Author < ActiveRecord::Base
    has_one :book
  end
```

Notice that `book` is singular. This may seem intuitive, but it is very important to note when to use singular or plural cases when writing your associations. The Book model would remain the same in this case, reading `belongs_to: author` in the singular.

---

##has_many, through:

This association is often used to set up a many-to-many connection with another model. The declaring model can be matched with instances of another model _through_ a third, connecting model. For example, imagine a hospital with doctors that see many patients _through_ the patients' appointments. The diagram would look like this: 

![has many through](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sp5p3rdhp16dvndiltr0.png)

Each doctor has many patients _through_ the appointments table. The patient also has many doctors _through_ the appointments table. Here is the corresponding association code: 
 
```javascript
  class Doctor < ActiveRecord::Base
    has_many :appointments
    has_many :patients, through: :appointments
  end

  class Appointment < ActiveRecord::Base
    belongs_to :doctor
    belongs_to :appointment
  end

  class Patient < ActiveRecord::Base
    has_many :appointments
    has_many :doctors, through: :appointments
  end
```

Then new join models are automatically created for the newly associated objects. 

---

##has_one, through: 

The `has_one, through:` association is similar to the `has_many, through:` association because they both create join models automatically. The difference is in the syntax, and that there is a one to many relationship. In our example above, imagine a patient only had one doctor, through the patient's appointments: 

```javascript
  class Doctor < ActiveRecord::Base
    has_many :appointments
    has_many :patients, through: :appointments
  end

  class Appointment < ActiveRecord::Base
    belongs_to :doctor
    belongs_to :appointment
  end

  class Patient < ActiveRecord::Base
    has_many :appointments
    has_one :doctor, through: :appointments
  end
```

---

##has_and_belongs_to_many

This association is rarely used, and there is a blog post titled "[Why You Don’t Need Has_and_belongs_to_many Relationships](https://flatironschool.com/blog/why-you-dont-need-has-and-belongs-to-many/) explaining why. From the Rails docs: 

> The simplest rule of thumb is that you should set up a has_many :through relationship if you need to work with the relationship model as an independent entity. If you don't need to do anything with the relationship model, it may be simpler to set up a has_and_belongs_to_many relationship (though you'll need to remember to create the joining table in the database).

---

##Bonus: Polymorphic Association

Polymorphic association allows us to connect a model to multiple other models on a single association. Look at this table provided by the [Rails Active Record documentation](https://guides.rubyonrails.org/association_basics.html): 

![polymorphic](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lgkvm35odj0d9ll4hif4.png)

A polymorphic `belongs_to` declaration sets up an interface that any other model can use. For example, from an instance of an Employee model, a collection of pictures can be retrieved using @employee.pictures. You could also retrieve @product.pictures by the same logic.

Find more information, as well as helpful tips and tricks, in the [official documentation here](https://guides.rubyonrails.org/association_basics.html).