Ruby on Rails ActiveRecord Associations
Tags: rails, ruby, associations, database
Published: 2022-07-12 18:31:20

Much of the power of Ruby on Rails lies in creating good associations to keep our data well organized, so that it can be used efficiently.
![Association Symbols](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dn2ge1ohj5nr2xqi3h4j.png)

There are three main association types.

- **One-to-One Association**: One object is related with one and only object.
Example: If there are two entities `Person(Id, Name, Age, Address)` and `Passport(Passport_id, Passport_no)`. So, each person can have only one passport and each passport belongs to only one person.
![One-to-One Association](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jjjhyynptjr18z88q3t3.png)
 
    
- **One-to-Many Association:** One object has many objects and many objects belongs to the One object. 
Example: If there are two entity type `Customer` and `Account` then each `Customer` can have more than one `Account` but each `Account` is held by only one `Customer`. In this example, we can say that each Customer is associated with many Account. So, it is a one-to-many relationship. But, if we see it the other way i.e many Account is associated with one Customer then we can say that it is a many-to-one relationship.
![One-to-Many Association](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yam6r4ese89769992zed.png)
 

- **Many-to-Many Association:** Each object of the first class can be related to one or more than one object of the second class and a single object of the second class can be related to one or more than one object of the first class.
NOTE: For using Many-to-Many association we need a **joint table** as we can’t include many foreign keys to a table. A joint table serves as a way to make links between two different tables. The joint table will have foreign keys of each pair of related objects from the both tables.
Example: If there are two entity type `Customer` and `Product` then each customer can buy more than one product and a product can be bought by many different customers.
![Many-to-Many Association](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ovrdi6iki1aqeishiyqg.png)

## Association Method

- **One-to-One relationships**: `has_one, belongs_to`, `has_one :through`
- **One-to-Many relationships**: `has_many, belongs_to`
- **Many-to-Many relationships**: `has_and_belongs_to_many`, `has_many :through`

### **`belongs_to`** Association

 A belongs_to association sets up a connection with another model, and declares model "belongs to" one instance of the other model.

**Note:** When you define belongs_to inside a model, the other object that that belongs_to is not optional. If it belongs to it, then that other object has to be assigned. This happens because Rails adds a validation that check if the referenced object is present. Please also note that order versions of Rails do not do that.
You can disable this validation by passing `{:optional => true}` 

For example, if your application includes `person` and `passport`, and each `passport` can be assigned to exactly one `person`, you'd declare the `passport` model this way:

```ruby
class Passport < ApplicationRecord
  belongs_to :person # this validates the presence of the person object
end
```

```ruby
class Passport < ApplicationRecord
  belongs_to :person, optional: true # does not validates the presence of the person object
end
```

### **`has_one`** Association

A `has_one` association shows that another model is referenced to this model. That model can be fetched through this association.

For example, if each `person` in your application has only one `passport`, you'd declare the `person` model like this:

```ruby
class Person < ApplicationRecord
  has_one :passport
end
```

### **`has_many`** Association

A `has_many`association indicates a one-to-many connection with another model and often used with `belongs_to` on the other model. This association declares that each instance of the model has zero or more instances of another model.

For example, in an application containing `customers` and `accounts`, the `customers` model could be declared like this:

```ruby
class Customer < ApplicationRecord
  has_many :accounts
end
```

### **`has_many :through`** Association

A `has_many :through` association is used to set up a many-to-many connection with another model. This declares a model can be matched with zero or more instances of another model through a third model.
For example, consider a online shop where customers make purchases to get products. The association declarations could look like this:

```ruby
class Customer < ApplicationRecord
  has_many :purchases
  has_many :products, through: :purchases
end

class Purchase < ApplicationRecord
  belongs_to :customer
  belongs_to :product
end

class Product < ApplicationRecord
  has_many :purchases
  has_many :customers, through: :purchases
end
```

### **`has_one :through`** Association

A `has_one :through` association sets up a one-to-one connection with another model through a third model. This declares the model can be matched with one instance of another model through a third model.

For example, if each person has one passport, and each passport is associated with one passport_issue, then the models could look like this:

```ruby
class Person < ApplicationRecord
  has_one :passport
  has_one :passport_issue, through: :passport
end

class Passport < ApplicationRecord
  belongs_to :person
  has_one :passport_issue
end

class PassportIssue < ApplicationRecord
  belongs_to :passport
end
```

### **`has_and_belongs_to_many`** Association

A `has_and_belongs_to_many` association creates a direct many-to-many connection with another model, without the help of a third model and declares this model can be matched with zero or more instances of another model

For example, if your application includes assemblies and parts, with each assembly having many parts and each part appearing in many assemblies, you could declare the models this way:

```ruby
class Assembly < ApplicationRecord
  has_and_belongs_to_many :parts
end

class Part < ApplicationRecord
  has_and_belongs_to_many :assemblies
end
```

**Choosing Between `has_many :through` and `has_and_belongs_to_many`:** 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).

## Polymorphic Associations

A polymorphic association allows a model to belong to multiple other models. In this case, we might create a Profile model and a Blog model, and both have many references to Images.

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

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

class Blog < ApplicationRecord
  has_many :images, as: :imageable
end
```

We can consider polymorphic `belongs_to` declares that any models can set up an interface with model and use it. In this case we can retrieve an image from a profile instance using `@profile.image` and a collection of images from a blog instance using `@blog.images`

## Additional Features in ActiveRecords

### `:dependent => :destroy`

When the object is destroyed, destroy will be called on its associated objects.

Example: In this case when a user is deleted all the comments created by the user also gets destroyed

```ruby
class User < ApplicationRecord
	has_many :comments, dependent: :destroy
end

class Comment < ApplicationRecord
	belongs_to :user
end
```

### `:dependent => :delete_all`

The difference here is that :delete_all, like the delete_all method, is skipping the callbacks that are in that comment object. It just goes straight to the database, and writes SQL to delete them. Destroy is a safer choice, because comment may have callbacks as well.

```ruby
class User < ApplicationRecord
	has_many :comments, dependent: :delete_all
end

class Comment < ApplicationRecord
	belongs_to :user
end
```

## Joining Tables

Once we have associations between our models, we can start to work with them in interesting ways. And one of those ways is by joining tables during our queries. If you're familiar with working with databases, you'll know that there are times when we want to be able to join two different tables together during a query. So we can query columns on more than one table.

We can use SQL joins to query columns on several tables.

Example: The given code will return Products for which its category is active

```ruby
Product.joins(:category).where('categories.active = 1')
# or you can use a hash format
Product.joins(:category).where(categories: {active: true})
```

**Here are the few ways we can join a table:**

- **Using a String SQL Fragment:** We can provide the raw SQL specifying the JOIN clause
`Author.joins("INNER JOIN books ON books.author_id = authors.id AND books.out_of_print = FALSE")`
- **Joining a Single Association:**
`Product.joins(:category)`
- **Joining Multiple Associations:**
`Product.joins(:category, :inventory)`
 
By joining tables together with the joins method, you have the ability to start working with your associations in interesting ways.

> Thanks For Reading, Follow Me For More
> Share your suggestions, doubts and feedback in the comments section!