Using the paranoia gem when joining tables

Something I learned today about joining two tables that both use acts_as_paranoid

If you want to make your Rails app feel like an object has been deleted but actually keep the data intact, you can use the paranoia gem to soft delete objects.

By default, this adds a timestamp into a deleted_at attribute. Trying to lookup or access a record with deleted_at set won’t work unless you write specific code. This deletes the record without actually deleting the data.

In a recent project, I had to find all the objects of one Model that had been deleted, but who had a relationship with another object that wasn’t deleted.

It turns out paranoia gives us this for free!

Lets imagine two models, Post and Comment;

class Post < ActiveRecord::Base
  acts_as_paranoid
  has_many :comments
end

class Comment < ActiveRecord::Base
  acts_as_paranoid
  belongs_to :post
end

If we want to see deleted comments, but only ones that were attached to non-deleted posts, we can do the following.

Comment.only_deleted brings back only deleted items (only_deleted is given to us through the paranoia gem).

Because Posts also use the paranoia gem, chaining them into our call with a joins automatically gives us what we want!

Comment.only_deleted.joins(:post)

For any ActiveRecord query we can call to_sql to see what it is generating under the hood.

Comment.only_deleted.joins(:post).to_sql gives us;

SELECT "comments".* FROM "comments" INNER JOIN "posts" ON "posts"."deleted_at" IS NULL AND "posts"."id" = "comments"."post_id" WHERE "comments"."deleted_at" IS NOT NULL

Note comments.deleted_at IS NOT NULL (has been deleted) but posts.deleted_at IS NULL (has not been deleted).

This is incredibly handy!

Recent posts View all

Web DevProductivity

Keeping on top of website updates

Learn what website updates are, what they entail, why they are important, and how we can help

Freelancing

Getting the most out of your agency

Here are some tips based on years of working with, for, and as an agency on how to get the most out of any work you do.