Enhancing has_many Associations in Ruby on Rails: the Dependent Option

While Ruby on Rails comes with smart defaults that usually do the trick, there might be moments when you feel like customizing how the has_many association reference behaves. Thankfully, you can easily do this by passing some options, like the :dependent one. Let’s see how it works and the most common parameters this option accepts.

During this article, we will be using these models for the examples:

class RentalCompany < ApplicationRecord
has_many :cars
end

class Car < ApplicationRecord
belongs_to :rental_company
end

dependent: :destroy

When a parent object (the one with the has_many relationship) gets destroyed, all the associated objects will be destroyed too. Remember that when you destroy an object, the callbacks will be executed.

class RentalCompany < ApplicationRecord
has_many :cars, dependent: :destroy
end

class Car < ApplicationRecord
belongs_to :rental_company

before_destroy :notify_car_owner #callback
end

In this example, when you delete a Rental Company, Ruby on Rails will automatically call the destroy method in every car associated with that Rental Company, but first, it will execute the callback and notify car owners that their car has been removed from the company listings.

dependent: :delete_all

When a parent object gets deleted, all the associated objects will be also deleted directly from the database, making it more efficient in terms of database operations. It’s important to notice that when using delete, callbacks won’t execute.

class RentalCompany < ApplicationRecord
has_many :cars, dependent: :delete_all
end

class Car < ApplicationRecord
belongs_to :rental_company

before_destroy :notify_car_owner #callback
end

In this example, when you delete a Rental Company, Ruby on Rails will delete all the associated cars but the before_destroy callback won’t be executed.

dependent: :nullify

Sets the foreign key to NULL. Useful if you don’t want to physically delete associated objects but want to disassociate them.

class RentalCompany < ApplicationRecord
has_many :cars, dependent: :nullify
end

In the example, when the Rental Company is destroyed, the cars will have their foreign key field set to NULL (`rental_company_id` in most cases).

:restrict_with_exception

This is a way to enforce that the parent object cannot be deleted if there are associated records, and it raises an exception to notify you of the restriction.

class RentalCompany < ApplicationRecord
has_many :cars, dependent: :restrict_with_exception
end

So, for example, when you attempt to delete the Rental Company, it causes an ActiveRecord::DeleteRestrictionError exception to be raised if there are any associated cars.

# Example raising an exception
rental_company = RentalCompany.find(1)

begin
rental_company.destroy
rescue ActiveRecord::DeleteRestrictionError => e
puts "Error: #{e.message}"
end

This will output something like:

Error: Cannot delete record because dependent cars exist

So far, we’ve explored some of the frequently used parameters applicable to the :dependent option in a has_many relationship in Ruby on Rails. I trust this walkthrough has provided you with a clearer understanding of how you can tailor the behavior of the has_many association reference to suit your specific needs. Feel free to ask in the comments if you have any doubts.