Soft delete records with Paranoia
How to use Paranoia to makes soft deleting records in Ruby on Rails
What'll we learn:
- Introduction to Paranoia gem
- Installation
- How to use Paranoia functionality?
- Conclusion

Introduction
- Paranoia is a gem that allow you to hide and restore records without actually deleting them and can recover them later if you want.
- This gem re-implementation of ActsAsParanoid
Installation
Add paranoia gem to Gemfile:
gem 'paranoia', '~> 2.4'
Then run:
bundle install
Create migration to add soft-delete for Post model:
bin/rails generate migration AddDeletedAtToPost deleted_at:datetime:index
The migration will add column deleted_at to Post model:
class AddDeletedAtToPost < ActiveRecord::Migration[6.0] def change add_column :posts, :deleted_at, :datetime add_index :posts, :deleted_at end end
Run migration:
rails db:migrate == 20201016152809 AddDeletedAtToPost: migrating ==================== -- add_column(:posts, :deleted_at, :datetime) -> 0.0333s -- add_index(:posts, :deleted_at) -> 0.0270s == 20201016152809 AddDeletedAtToPost: migrated (0.0605s) ===========
Usage
Enable this functionality for Post model:
class Post < ActiveRecord::Base acts_as_paranoid [...] end
Paranoia will changes the default_scope of model, that mean Post.all will not include the deleted records.
Soft Delete a record:
When we destroy a record, it'll set current timestamp to deleted_at column
post.deleted_at # => nil post.destroy # => post post.deleted_at # => [current timestamp] Fri, 16 Oct 2020 15:39:19 UTC +00:00
Restore a record:
It'll update { deleted_at => nil }
post.restore or Post.restore(id)
Restore a record and their dependently destroyed Associated records:
post.restore(:recursive => true) or Post.restore(id, :recursive => true)
Find a deleted post
Post.find(id) # => ActiveRecord::RecordNotFound Post.unscoped.find(id) || Post.with_deleted.find(id) # => post
Filtering:
Find all records, includes deleted posts:
Post.with_deleted
Find records, exclude deleted posts:
Post.without_deleted
Find only the deleted posts:
Post.only_deleted
Really Delete a Post
If you really want it gone, call really_destroy!:
post.really_destroy!
Conclusion
In this article, I already guided about how to soft-delete records instead of permanent-delete records in database. Paranoia actually is a useful gem, that makes soft deleting easier.