Handling associated records when an object is deleted
Tags: activerecord, beginners, backend
Published: 2023-05-23 19:00:57

In phase 3 of my coding boot camp, we scratched the surface of database management with the help of Active Record. I have to say, Active Record is the real MVP and maybe I'm not looking in the right places but I don't see it getting a ton of love online so shout out to Active Record. Until it came into the picture I found myself thinking things like "Maybe the backend isn't for me", "There's no way people write this much SQL" and "There has to be a better way". Fortunately, that last thought was correct. Active Record provides us with a powerful set of tools to simplify many processes, including how to handle children of objects you delete from your database. This came in handy when working on a project and in this blog we will explore ways to handle all records associated with an object using some built-in features of Active Record. 

First things first - for there to be a parent/child relationship in your database, your tables have to be associated. Associations define relationships between different models in a database. The most common association types include `has_many`, `belongs_to`, `has_one`, and `has_and_belongs_to_many`. These associations establish connections between tables, allowing us to navigate relationships and fetch associated data with ease. Your association is declared in your model classes like so:

```
class Owner < ActiveRecord::Base

has_many :items

end
```

```
class Item < ActiveRecord::Base

belongs_to :owner

end
```

This example is a one-to-many association where an Owner has many Items and each item belongs to one owner. Associations give us access to methods that simplify database interactions such as effortlessly querying, building, creating, updating, and deleting associated objects. 

The `:dependent` option in Active Record associations allows you to specify the behavior of associated records when the parent object is deleted. The cool thing is,  it provides flexibility and control over the deletion process with a few different options. Here is an overview of what they are:

-  `:destroy`: Calls the `destroy` method on each associated record, triggering associated callbacks and validations. This option allows for cascading deletion of associated records. 

(Side note: Cascading deletion simply refers to the automatic deletion of associated records when the parent object is deleted. This deletion "cascades" down to the associated records, ensuring data integrity and consistency. It simplifies the process of deleting complex data structures and prevents orphaned records.)

-  `:delete_all`: For scenarios where performance is critical, the `:delete_all` option comes in handy. It performs a single SQL DELETE statement to directly remove all associated records without triggering callbacks or validations. This approach offers a significant performance boost when deleting a large number of associated records.


-  `:nullify`: In certain cases, rather than deleting associated records, we may prefer to nullify the foreign key column of those records. The `:nullify` option achieves this by updating the foreign key column of associated records to `NULL` without deleting them. This option preserves the data.


-  `:restrict_with_exception` and  `:restrict_with_error`: To enforce constraints on deletion, Active Record provides `:restrict_with_exception` and `:restrict_with_error`. When the `:restrict_with_exception` option is used, an exception is raised if associated records exist, preventing the deletion of the parent object until the associated records are removed. On the other hand, `:restrict_with_error` adds an error to the parent object, preventing its deletion.


Example usage:

```
class Owner < ActiveRecord::Base

has_many :items, dependent: :destroy

end
```

In the above example, when an owner is deleted, all associated items will also be destroyed due to the `:dependent` option set to `:destroy`. 

These options offer flexibility in managing associated records during deletion, allowing you to choose the approach that best suits your needs. Remember to consider the impact on your application's performance when if you may need that data in the future when deciding on a `:dependent` option!