Paranoia is a gem that allows you to hide records instead of destroying them. You can recover them later if you want. It’s a very simple (one file with about 300 lines of code) reimplementation of ActsAsParanoid.
I assume you have a Rails app with User, Conversation and Message models created, with basic views added with conversations showing authors and messages
Very simple gem
Easy to debug (only one file)
It does what it claims to do
Actively maintained
Nice documentation
Sometimes unintuitive
In some cases it’s probably better to implement your own solution
Add paranoia gem to your Gemfile:
gem 'paranoia', git: 'git@github.com:rubysherpas/paranoia.git', branch: 'core'
You add it like that because the newest release doesn’t include some features that will be used in this tutorial.
Now, let’s say that you want to delete an user, but his messages should still be displayed with his name as an author (in your view you’ll have something like message.user.name). If you removed that user, when trying to display his messages you would get an error:
undefined method `name` for nil:NilClass
In order to avoid that, instead of destroying records you should mark them as deleted. It’s called soft deleting and it’s what paranoia gem is all about.
To enable this behaviour for User model, add this line to it:
class User < ActiveRecord::Base
acts_as_paranoid
[...]
You also need to generate and run this migration:
rails generate migration AddDeletedAtToUsers deleted_at:datetime:index
rake db:migrate
From now on, calling destroy on any user will set deleted_at to a current date instead of actually destroying the record.
But, if you try to softly delete an user and display his messages, you’ll still get the same error as before. That’s because paranoia gem changes the default_scope of a model, so every query will treat softly deleted records as if they weren’t there (WHERE "users"."deleted_at" IS NULL will be added to queries). Of course if you love your default_scope and you don’t ever want it to change you can achieve that:
# not available in the newest release, you have to add paranoia gem as in step 1
acts_as_paranoid without_default_scope: true
You can also access your softly deleted user record in other ways:
by overriding user method in Message model:
def user
User.unscoped { super }
end
belongs_to :user, -> { with_deleted }
add_index :users, :some_column, where: "deleted_at IS NULL"
User.restore(message.user.id)
Message.user.restore
class User < ActiveRecord::Base
acts_as_paranoid
has_many :messages, dependent: :destroy
[...]
User.restore(user_id, recursive: true)
user.restore(recursive: true)