How to Use the Destroy and Delete Methods in Rails
On the surface, basic API operations are very straightforward. A normal app will usually follow the CRUD format of allowing users to make requests to Create, Read, Update and Delete resources. While the request methods are fairly uniform, the way in which the API, or backend of your app, implements them can vary drastically.
When we make a DELETE request to a Rails API, there are two basic methods that this call can trigger. The two calls are delete and destroy. To a beginner these may seem to accomplish the same action, deleting a resource. However, looking closer at the Rails docs we find that they are different.
Before we dive into the nuances of these methods, let’s create a hypothetical situation to highlight these method’s differences.
You are currently an engineer at a high growth social media startup. You are on a team that handles managing user profiles and their associated posts and content. Recently you were assigned to build a controller action that allows users to delete their profiles when they choose to leave the platform. The feature was a quick build and has now been deployed for weeks.
One day your manager calls you in to talk about an issue with posts that are missing a profile. Though users have been able to delete their profiles, their content is still on the platform. When a current user tries to navigate to the a post’s profile, they are met with a 404. Your manager wants to know why these posts still exist and how to fix the problem going forward.
Delete
In this scenario you most likely set up your controller’s ‘delete’ action using the Rails Model delete method. This method is great for scaling as it is very fast, but it is fast at a cost. While the other common ‘delete’ method ties into the model lifecycle and allows for using model callbacks, delete lacks this ability in order to stay quick. Whatever model instance or record delete is called upon, it removes this record from the model database table and moves on to the next operation.
This is great for speed, but has the side effect of leaving us with orphan records. Orphan records are any child records that are not deleted when a parent record is deleted. Let’s take a look at the following example to see visually how this happens:
Here we see that we remove the profile record, but do not go any deeper to remove our associated posts. Again, while we have accomplished our goal of removing the profile, we have left a lot of records behind that will bloat our database and lead to inconsistencies in how our app works in the future.
Destroy
If we care about removing all records associated with our designated profile then we need to use destroy. Destroy, unlike delete, allows us to access the models lifecycle which gives us access to all sorts of callbacks. These callbacks will help us to check for any dependent records and remove them before deleting our record.
How this works can be seen in the following figures. First, we start the process of deleting our profile record:
Then we look at all dependent (child) records and delete them, one at a time:
Finally we delete our main profile record and we are set:
Knowing to use destroy instead of delete only gets you half way to our solution. To get the most out of our destroy call, we will need to add arguments to the relationship declaration on our model:
Here we declare on the Profile model that the profile has many posts, and that when the profile is deleted, we should destroy all the associated post model instances as well. It is important to note that we set dependent to destroy instead of something like delete. This allows our associated instances cleanup to work from the root (profile) to terminal nodes (our lowest relationship through a post).
Conclusion
If you want to be fast, use delete. If you want to be thorough, use destroy. Unless you are performing very complex and frequent data purges, you should always use destroy as the ability to access the model’s lifecycle will help ensure that your records are properly and fully deleted. Let me know in the comments about bugs you’ve found our issues you’ve experienced with incorrect delete vs. destroy method calls.
Notes
https://stackoverflow.com/questions/22757450/difference-between-destroy-and-delete