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.