The Dependent Option for Model Associations in Rails

Stephen McKeon
Tech at Power
Published in
4 min readJul 14, 2020

--

A simple way to level up your Ruby on Rails apps.

Recently when developing a Rails application, I ran into a snag when deleting an instance of a parent model (e.g. Artist). Its related records (or children; e.g. Songs) stuck around. This caused several bugs wherever those related records (Songs) were called because its foreign key (artist_id) tried to load an associated artist that no longer existed. This forced me to manually delete the broken records in Rails console and implement a method to delete each associated record upon deletion of a parent object ( it reeked of code smell). But there’s a better way…

Enter model association dependencies.

The has_many, belongs_to, and has_one relationships support the :dependent option (which is added to an association like :validate or :through would be). This allows the developer to specify how associated records should be deleted when the owner is deleted.

Let’s hit the ground running and start with an example:

An Artist has_many songs and a Song belongs_to an Artist. Let’s consider this:

johnny_cash = Artist.create(name: "Johnny Cash")ring_of_fire = Song.create(title: "Ring of Fire", artist: johnny_cash)

However, if johnny_cash is destroyed, that leaves ring_of_fire with an artist_id pointing to an Artist that no longer exists, stuck in limbo! So calling something like Arist.find(ring_of_fire.artist.id) will return:

ActiveRecord::RecordNotFound (couldn't find Artist with 'id'=2)

This will be an issue for any method that calls on aSong's Artist. You may want to also delete any songs associated with an Artist when you delete it. There is a very eloquent solution to this and where the:dependent option comes into play:

Now, when johnny_cash is destroyed, its associated songs are also destroyed:

destroy is a great start, but Rails includes a few options for dependent that allows us to customize our apps even further. The options for dependent include:

  • :destroy causes all the associated objects to also be destroyed
  • :delete or :delete_all (:delete_all is used with has_many relationships) causes all the associated objects to be deleted directly from the database (so callbacks will not execute)
  • :nullify causes the foreign key to be set to NULL. Polymorphic type column is also nullified on polymorphic associations. Callbacks are not executed. This is useful when you don’t want to delete or destroy an associated object, but clear the foreign key of its owner
  • :restrict_with_exception causes an ActiveRecord::DeleteRestrictionError exception to be raised if there are any associated records
  • :restrict_with_error causes an error to be added to the owner if there are any associated objects

Conclusion

The dependent option is a handy tool that can help in a variety of different ways (with its different options) that makes life as a Rails developer that much sweeter. Deleting an object can leave its related records broken with foreign keys that point to instances that no longer exist. The dependent option for Rails associations allows related instances to be destroyed or deleted, foreign keys nullified, and can even prevent objects from being deleted if there are associated objects. Give the dependent option a shot in your next project, you won’t be disappointed!

This post is written by a Power Code Academy Student Developer.

--

--