Back to Course

Spot the Tax · Card 3 of 20

:destroy runs in Ruby, :delete_all runs in SQL

Why deleting one user with 50,000 events can take minutes, and how to pick the right cascade for the work.

The code

What will this cost you in six months?

class User < ApplicationRecord
  has_many :events, dependent: :destroy
  has_many :messages, dependent: :destroy
  has_many :reactions, dependent: :destroy
end

# In the controller:
def destroy
  current_user.destroy
  redirect_to root_path
end

The problem

When you delete a user that has 50,000 events, dependent: :destroy doesn't just delete the events. It loads each event into memory as a Ruby object, fires every destroy callback on that object, and then sends a separate DELETE statement for that one row. So a single user.destroy ends up doing 50,000 of everything. What should be a fast operation takes minutes, sometimes times out halfway through, and leaves your data in a half-deleted state that's painful to clean up.

Take a moment. Before revealing, think about how you'd actually delete a user with 50,000 events. What's the difference between deleting in Ruby and deleting in SQL, and when does each make sense?