[Awesome Ruby Gem] Use paranoia or acts_as_paranoid gem soft delete to hide and restore records without actually deleting them

paranoia or acts_as_paranoid

paranoia is a re-implementation of acts_as_paranoid for Rails 3/4/5, using much, much, much less code.

When your app is using Paranoia, calling destroy on an ActiveRecord object doesn’t actually destroy the database record, but just hides it. Paranoia does this by setting a deleted_at field to the current time when you destroy a record, and hides it by scoping all queries on your model to only include records which do not have a deleted_at field.

Use paranoia gem according to the RubyGem latest update:

GitHub latest update RubyGem latest update Comments
paranoia Now 2.4.3 - December 16, 2020 Paranoia will continue to accept bug fixes and support new versions of Rails but isn’t accepting new features.
acts_as_paranoid Now 0.7.0 - August 29, 2020

Installation

You can install it as a gem:

1
2
$ gem install paranoia
# OR gem install acts_as_paranoid

or add it into a Gemfile (Bundler):

1
2
3
4
5
6
7
8
9
10
# Gemfile

# rubysherpas/paranoia: acts_as_paranoid for Rails 3, 4 and 5
# https://github.com/rubysherpas/paranoia
gem 'paranoia', '2.4.3'

# Or use acts_as_paranoid
# ActsAsParanoid/acts_as_paranoid: ActiveRecord plugin allowing you to hide and restore records without actually deleting them.
# https://github.com/ActsAsParanoid/acts_as_paranoid
# gem 'acts_as_paranoid', '0.7.0'

Then, run bundle install.

1
$ bundle install

Migration

Create migration,

1
2
3
4
$ bin/rails generate migration AddDeletedAtToUsers deleted_at:datetime:index
Running via Spring preloader in process 2946
invoke active_record
create db/migrate/20200811215130_add_deleted_at_to_users.rb

Show the migration 20200811215130_add_deleted_at_to_users.rb.

1
2
3
4
5
6
class AddDeletedAtToUsers < ActiveRecord::Migration
def change
add_column :users, :deleted_at, :datetime
add_index :users, :deleted_at
end
end

Run db migrate.

1
$ bin/rails db:migrate

Usage

Enable ActsAsParanoid.

1
2
3
4
5
6
7
8
9
10
11
12
13
class User < ActiveRecord::Base
acts_as_paranoid
end

# or inherit from ApplicationRecord
# class ApplicationRecord < ActiveRecord::Base
# self.abstract_class = true
#
# acts_as_paranoid
# end

# class User < ApplicationRecord
# end

Magic Column

By default, ActsAsParanoid assumes a record’s deletion is stored in a datetime column called deleted_at.

Filtering

If a record is deleted by ActsAsParanoid, it won’t be retrieved when accessing the database.
So, Paranoiac.all will not include the deleted records.

When you want to access them, you have 2 choices:

1
2
User.only_deleted # retrieves only the deleted records
User.with_deleted # retrieves all records, deleted or not

Caveats

Watch out for these caveats:

  • You cannot use scopes named with_deleted and only_deleted

  • You cannot use scopes named deleted_inside_time_window, deleted_before_time,
    deleted_after_time if your paranoid column’s type is time

  • You cannot name association *_with_deleted

  • unscoped will return all records, deleted or not

References

[1] rubysherpas/paranoia: acts_as_paranoid for Rails 3, 4 and 5 - https://github.com/rubysherpas/paranoia

[2] paranoia | RubyGems.org | your community gem host - https://rubygems.org/gems/paranoia/

[3] ActsAsParanoid/acts_as_paranoid: ActiveRecord plugin allowing you to hide and restore records without actually deleting them. - https://github.com/ActsAsParanoid/acts_as_paranoid

[4] acts_as_paranoid | RubyGems.org | your community gem host - https://rubygems.org/gems/acts_as_paranoid