Rails Destroy vs Delete vs Delete All vs Destroy All

Rails documentation says

Destroy an object (or multiple objects) that has the given id. The object is instantiated first, therefore all callbacks and filters are fired off before the object is deleted. This method is less efficient than delete but allows cleanup methods and other actions to be run.

The destroy on an active record object delete the record from the database and triggers the active record callbacks. Such as after_destroy, before_destroy. But the delete executes a direct database delete query hence skipping all the callbacks. This makes delete faster than destroy

Let’s look at some example

class Post
  before_destroy :do_something1
  around_destroy :do_something2
  after_destroy :do_something3

  has_many :comments, dependent: :destroy

Calling the destroy on thePost record, Post.find(100).destroy

  • Delete the record from the database
  • Execute the respective callback methods before_destroy, around_destroy and after_destroy
  • Deletes the comments associated to post through the dependant: :destroy. Each comment is deleted by calling destroy on it

Now calling the delete on the Post record, Post.find(100).delete

  • Deletes the record from the database directly
  • Does not trigger any callbacks
  • dependent: :destroy is also skipped

As you can see this is the reason delete faster than destroy.

You should use delete carefully, becuase if there are callback methods on a model there is a reason for it and you might not want to skip those callbacks.

As we know has_many :comments, dependent: :destroy is triggered when we call the destroy on the Post record, and this, in turn, calls the destroy on each comment associated with the post (in reality comments are deleted first then the post)

In some cases, there can be hundreds of comments for a post. In such cases using delete over destroy for deleting the associated comments is a good idea. as it will be slow to delete each associated comment using destroy. This can be achieved by using dependent: :delete_all

class Post
  has_many :comments, dependent: :delete_all

dependent: :delete and dependent: :destroy_all are not a valid options
Valid dependent options are
:destroy, :delete_all, :nullify, :restrict_with_error, :restrict_with_exception

So far we have understood the difference between delete and destroy. We have also understood the differencedependent: :destroy and dependent: :delete_all

Let’s conclude what we know so far and more

post = Post.find(100)

  • post.destroy
      • Delete the post record from the database and callbacks methods are executed
  • post.delete
    • Delete the post record from the database. Callbacks are skipped, faster than destroy
  • post.comments.delete_all
    • Delete all the comments associated with the post in a single query. Callbacks are skipped
  • post.comments.destroy_all
    • Delete the comments associated with the post one by one using destroy. Callbacks are executed. This is equal to post.comments.each(&:destroy)
  • post.comments.delete(12345)
    • Delete the comment with id 12345. Callbacks are skipped
  • post.comments.destroy(12345)
    • Delete the comment with id 12345. callbacks are executed
  • post.comments.each(&:delete)
    • Delete the comments associated with the post one by one using delete. Callbacks skipped. Instead of this always use post.comments.delete_all since delete_all delete all the records in one single query

Leave a Reply

Your email address will not be published.