Yesterday, I started my very first job as a software engineer! It’s been super exciting, slightly terrifying, and sometimes overwhelming. I think one of the trickiest parts of starting as a new engineer at a company is the onboarding process.
It might seem kind of scary, but if you think about it, it’s actually pretty fun. You get to dive down a rabbit hole and look at production code that you didn’t write. It’s getting a new puzzle that you haven’t solved yet: you try to figure out how one thing connects to another, where modules and methods exist, how things are namespaced, not to mention learning about new frameworks and gems. I feel like I’m entering into new dimensions and travelling through a space-time continuum or something. This also might be attributed to the fact that I’ve been listening exclusively to the Interstellar soundtrack for the past two days, but whatever – you get the point.
My favorite part of the onboarding process is how much I’ve been learning. Every new class or module definition brings a new piece of the puzzle that I’ve never seen before, but can’t wait to learn about. It’s kind of crazy that I get paid to read and learn all day, every day – that’s the dream, right?
Anyways, all of this is to say that I’ve found and learned about some cool stuff! For example this little ditty: acts_as_paranoid
. I saw this in a class definition and my first thought was literally: Damn, that’s a great name for a validation! But as it turns out, it’s not actually a validation – it’s Rails magic!
Start acting paranoid!
Okay, I lied: acts_as_paranoid
not actually magic – it’s a Rails ActiveRecord plugin. But it’s still pretty magical, you guys! So, what does it do? Well, it helps you be less paranoid about deleting stuff by accident (hence the name). Essentially, acts_as_paranoid
allows you to make soft deletes in Rails. That means that it gives you the flexibility to delete an object without actually deleting it from the database.
Does this sound like black magic yet? Just wait, you’re about to see some real magic.
So…how do I starting acting paranoid?
In my example, I’ll be implementing acts_as_paranoid
on some Book
objects in my eCommerce bookstore app. Using acts_as_paranoid
is relatively simple. You can break it down into two simple steps:
First, add acts_as_paranoid
to your class definition:
1 2 3 |
|
Then, add a column to the database for that class called deleted_at
, which is set to a datetime
format:
1 2 3 4 5 |
|
Ok, I’m getting paranoid now – how does this work?
So, we have another column in our Books
table that has a deleted_at
column with a type of :datetime
. Now, this is where the magic happens: the acts_as_paranoid
plugin actually overrides ActiveRecord’s find
, count
, and destroy
methods. So now when we call the destroy
method on a Book
object, instead of actually deleting the object, the object’s deleted_at
field will be set to the current date and time.
And, if we call the find
method on all of our Book
objects, the one we just “deleted” won’t show up! Instead, only the objects that don’t have a value in their deleted_at
column will render.
So, calling @book.destroy
doesn’t delete a row from the database; it actually just updates the row by giving a datetime to the object’s deleted_at
field. If you’re into SQL queries, this is what’s going on:
UPDATE books SET deleted_at = '2015-01-27 19:36:16' WHERE (id = 50)
The Book
object with an id of 50
isn’t actually deleted from the database, even though it will appear so in all of our views, and to our users/admins.
But who needs soft deletes, anyways?
I actually didn’t realize the use case for soft deletes at first. But it turns out that they are incredibly helpful when building out large, more complicated Rails applications.
It’s important to remember that Ruby is an object-oriented programming language. Any object that has an association with another object inherently relies upon it. In my bookstore app example, a Book
object would belong to a Order
object, and also be associated with a User
object of some sort. If you think about the appliation on a broader, less granular level, you might realize that deleting any given Book
object could actually have serious repercussions.
For example, you might want to see a Book
object that was ordered in the past, even if that Book
has since been deleted from a store. Perhaps you want to view the details of a Shipment
object, even if that shipment was cancelled. Or, you might want to see an order that was placed by a User
who may have deactivated their account months ago.
The acts_as_paranoid
plugin helps you access all of this information, without keeping you up at night, wondering whether you deleted the wrong row from the database. Because honestly, who has time for that? Not this kitty, for sure:
tl;dr?
- The
acts_as_paranoid
plugin modifies ActiveRecord methods and allows you to implement soft deletes on your Ruby objects. Just remember to include it in your class definition and add adeleted_at
column to your migration, with a type ofdatetime
. - Want to see another example of disabling records using
acts_as_paranoid
? Check out this blog post. - To read more about
acts_as_paranoid
and its many caveats, check out the easy-to-follow documentation.