The Slippery Slope Of Associations
The Association Principle is when we mentally connect things together , and then automatically follow the links we have created. We create associations to simplify our decision making process. And sometimes , the associations we create are wrong.
Here's a scenario. You go to the store to buy refreshing bottle of cold-pressed juice. You find one in the fridge and proceed to read the ingredients. Then, you see another flavor on the shelf and decide to buy that instead. By the time you get in your car , you notice the juice you bought is made from concentrate. Tsk tsk , you didn't read the ingredients the second time.
Well , what happened? You mentally associated the second juice with cold-pressed juices. Why? Because it was positioned next to the original bottle you picked up. Thus , you did not read the label and ended up with an undesirable outcome.
Learning occurs through the failures which we experience , not our successes. And similarly to the juice fiasco , I learned the pitfalls of the association principle while using Active Record's destroy method.
What is Active Record?
Active Record is a very powerful ORM in the Ruby on Rails library. It uses the convention over configuration paradigm to facilitate DRY code ,allowing the developer to focus on higher order tasks. Some of the most powerful macros within Active Record are Associations.
Associations are a set of macro-like class methods for tying objects together through foreign keys
Associations unlock a multitude of class methods, which make it easier to interact with and manipulate associated records through the relationships established between data tables. One of these methods being the destroy method. Let's explore the intricacies of the destroy method through a few examples I pulled from my most recent project , Flood Mail.
Flood Mail is a messaging platform built around game theory principles. Each user has complete control over their data. Delete a message , and it is deleted for both users. If a user deletes their account , then all associated data is deleted too.
Table Associations
If you're not familiar with table associations ,check out this page here.
Calling Destroy on an Object
According to the Ruby docs , the destroy method "Deletes the record in the database". Simple enough. We call it on an instance and ActiveRecord removes it from the database.
For the sake of this example , let's assume the Email Threads table is not referenced in any other table. The destroy method will function as follows.
Now , in the context of Flood Mail's backend, Email Threads are referenced in 2 other tables : Messages , and User Email Threads. Unless we setup the proper associations , the destroy method will throw an error.
In this example , Rails is attempting to save us from ourselves. If we remove the object in the example above , then we will have orphaned records in the dependent database tables.
Using Destroy Method with Associations
To remedy this , we use dependent: :destroy option inside our Email Thread model. Now , whenever we destroy an Email Thread , the destroy method will be called on all associated records as well. The result of calling the destroy method is slightly different now , but it's easy enough to remember.
Using Destroy Method with Join Tables
This example builds on the previous. We assume we have all the proper associations setup in our Models; therefore, we shouldn't receive any errors or orphaned messages. We want to destroy all the associated messages for our selected email thread. Since this is a collection of messages, we use the destroy_all syntax.
Destroy and destroy_all will always call the destroy method of the record(s) being removed so that callbacks are run.
Our destroy method has now removed every record in our collection of messages. If we try to find one of the deleted records ,we should expect an error.
Using the Destroy Method on Join Tables PT.2
Let's apply the same logic from our previous example to a user object. We'll assign the first user the variable user , and we'll delete the user's collection of email threads. Exactly as we did with the messages collection in for email thread.
And now if we try to find one of the deleted email threads , we should expect an error. Right?
The "Gotcha" Moment
Yet again we've been bamboozled by the association principle. Why are we able to find the record , it should have been destroyed? Well , let's dive into the Ruby on Rails docs to find out what actually gets deleted when we use these methods.
As it turns out , the join records are being deleted. If we want to delete the associated records themselves ,we will need to iterate over our collection and call the destroy method on each object.
user.email_threads.each {|e| e.destroy}
In Conclusion
By now , we've learned to should measure twice and cut once. By understanding what the destroy method is doing in different use cases , we'll avoid the possibility of creating orphaned records and corrupting our database tables. We've learned how to setup the proper associations to delete records and their dependents , as well as any other associated records using Active Record methods.
Resources
Flood Mail Repository
Active Record Associations
Ruby on Rails Active Record Documentation
Top comments (0)