Ruby on Rails: Don't delete, tombstone
In many web apps, things need to be deleted (no way!). But actually deleting records from your database has some side effects that aren’t immediately obvious:
- Undelete isn’t possible without additional work
- In small, simple apps, you may not have any other record of deleted rows
- You may be able to improve your product based on what has been deleted
- Extra work is required to “reactivate” deleted users or other models with their former data attached
One easy way to deal with this is with tombstones. A tombstone is simply a column in a table that marks whether a given record has been deleted.
This means that nearly all queries will need to filter based on this column to make sure it isn’t reading “deleted” (tombstoned) data. How annoying!
Fortunately, in Rails it is easy to separate out this concern. We can define a mixin called tombstoneable
such that any ActiveRecord model that mixes it in will automatically filter out deleted records by default, and add some easy methods to query for tombstoned records as well.
Make it work
Create a new file lib/mixins/tombstoneable.rb
:
Nice! The magic is in the included
block. We augment the default scope to always look for records that have not been deleted. If we wish to include deleted records as well, we can use the include_deleted
scope:
Or if we wish to only select deleted (tombstoned) edges, we can do that too:
Now mix it in
We never finished actually mixing this in to a model. Let’s assume we have a model called User. Only one line is needed to mix in the tombstoning behavior:
And add the column
We also need to make sure the database has a column to track which records have been deleted. This will be necessary for each model we wish to make tombstonable. From the command line:
Then modify the generated file to add a default and make the column NOT NULL
:
And run the migration:
That’s it!
I have found this to be a useful practice. Let me know how your experiences go (or have gone previously) in the comments. Enjoy your not-quite-deleted records!