Rails: Destroying vs Deleting

Posted . Visible to the public.

Rails offers several ways to remove records. They differ in whether they instantiate records, fire callbacks (including dependent: associations) and how they manage relation state afterward.

destroy_all

This is the definition of destroy_all:

# ActiveRecord::Relation
def destroy_all
  records.each(&:destroy).tap { reset }
end
  • records evaluates SQL, caches result
  • .each(&:destroy) iterates the cached Array, returns it
  • .tap { reset } calls Relation#reset, clears records and loaded, returns the Array unchanged

each(&:destroy) vs destroy_all

Both methods snapshot upfront, but the other does not reset the cache.

relation = Post.where(archived: true)

relation.destroy_all
relation.loaded?  # => false  (reset clears cache)
relation.count    # forces a new query

relation.each(&:destroy)
relation.loaded?  # => true   (stale destroyed objects remain cached)
relation.count    # does not query again

Irrelevant when the scope is called fresh each time (cleanup jobs), matters if reusing the relation variable.

destroy vs delete

dependent: options are registered as before_destroy callbacks. They only fire through destroy as it actually instantiates the records, never through delete as it's a pure SQL deletion.

delete_all deletes the records in bulk and also does not instantiate records nor does it run callbacks.

Example:

class Post < ApplicationRecord
  has_many :comments, dependent: :destroy  # before_destroy callback
end

post.destroy     # deletes post AND all comments (callback fires)
post.delete      # comments orphaned
Post.delete_all  # bulk SQL deletion, all children of posts orphaned
Profile picture of Felix Eschey
Felix Eschey
Last edit
Felix Eschey
License
Source code in this card is licensed under the MIT License.
Posted by Felix Eschey to makandra dev (2026-04-09 07:37)