Skip to main content Link Search Menu Expand Document (external link)

Soft Kill

Dealing with a record that has relation is sometimes tricky. For example, you deleted a post that have categories, when you try to access the category of that deleted post, it will have an error because it will find its parent, which is now gone. To solve this problem, we will use Soft Kill.

Table of contents

  1. What is Soft Kill?
  2. Creating Soft Kill

What is Soft Kill?

Soft kill is the means of overriding the destroy action and keeping the deleted record in the database, but is no longer visible to the user. This method is useful if you or another user accidentally delete something and want to recover it.

Creating Soft Kill

To make a soft delete method, first we need to add a deleted_at attribute with type datetime to posts.

 root@0122:/usr/src/app# rails g migration add_deleted_at_to_posts deleted_at:datetime
      invoke  active_record
      create    db/migrate/xxxxxxxxxxxxxx_add_deleted_at_to_posts.rb

Add default value nil before migrating the file.

# db/migrate/xxxxxxxxxxxxxx_add_deleted_at_to_posts.rb

class AddDeletedAtToPosts < ActiveRecord::Migration[7.0]
  def change
-   add_column :posts, :deleted_at, :datetime
+   add_column :posts, :deleted_at, :datetime, default: nil
  end
end
 root@0122:/usr/src/app# rails db:migrate
== xxxxxxxxxxxxxx AddDeletedAtToPosts: migrating ===========================
-- add_column(:posts, :deleted_at, :datetime, {:default=>nil})
   -> 0.0071s
== xxxxxxxxxxxxxx AddDeletedAtToPosts: migrated (0.0073s) ==================

Override destroy method in posts model.

# app/models/post.rb

class Post < ApplicationRecord
+ default_scope { where(deleted_at: nil) }

  validates :title, presence: true
  validates :content, presence: true

  has_many :comments
  has_many :post_category_ships
  has_many :categories, through: :post_category_ships
+
+ def destroy
+   update(deleted_at: Time.now)
+ end
end

Read Carefully:

Instead of deleting the post record, we are overriding the destroy method to only update the deleted_at with current time of deletion. The deleted_at attribute will serve as indicator if your comment is deleted or not.

Afterwards, we included a scope (default) for filtering the Post that have nil deleted_at. default_scope as its name implies is a method provided by ActiveRecord, which allows you to set a default scope for all operations done on a given model.

Let’s test our destroy method.

Reminder:

We will be using sandbox for this test. Sandbox is useful for testing out some code without changing any data. Type rails console --sandbox to enter the sandbox mode.

Loading development environment in sandbox (Rails 7.0.4)        
Any modifications you make will be rolled back on exit          
irb(main):001:0> post = Post.create(title: 'Testing Soft Kill', content: 'content for softkill')
  TRANSACTION (0.2ms)  SAVEPOINT active_record_1                                                                                                      
  Post Create (0.4ms)  INSERT INTO `posts` (`title`, `content`, `created_at`, `updated_at`, `deleted_at`) VALUES ('Testing Soft Kill', 'content for softkill', 'xxxx-xx-xx xx:xx:xx.xxxxxx', 'xxxx-xx-xx xx:xx:xx.xxxxxx', NULL)                                                                       
  TRANSACTION (0.2ms)  RELEASE SAVEPOINT active_record_1
irb(main):002:0> post.destroy
  TRANSACTION (0.3ms)  SAVEPOINT active_record_1
  Post Update (1.0ms)  UPDATE `posts` SET `posts`.`updated_at` = 'xxxx-xx-xx xx:xx:xx.xxxxxx', `posts`.`deleted_at` = 'xxxx-xx-xx xx:xx:xx.xxxxxx' WHERE `posts`.`id` = 51
  TRANSACTION (0.2ms)  RELEASE SAVEPOINT active_record_1
irb(main):003:0> post
=> 
#<Post:0x00007fc8fcd38408                                                                                                                         
 id: 51,                                                                                                                                          
 title: "Testing Soft Kill",                                                                                                                      
 content: "content for softkill",                                                                                                                 
 created_at: xxx, xx xxx xxxx xx:xx:xx.xxxxxxxxx UTC +xx:xx,                                                                                      
 updated_at: xxx, xx xxx xxxx xx:xx:xx.xxxxxxxxx UTC +xx:xx,                                                                                      
 deleted_at: xxx, xx xxx xxxx xx:xx:xx.xxxxxxxxx UTC +xx:xx>

Now we already integrated the soft kill in our application.


Back to top

Copyright © 2020-2022 Secure Smarter Service, Inc. This site is powered by KodaCamp.