Rails 6.1 adds support for destroying dependent associations in the background


The dependent: option which is built into Rails allows us to specify what happens to the associated records when their owner is destroyed.

Until now, the dependent: option accepted :destroy, :delete_all amongst other values.

:destroy and :delete_all are very similar with the only difference being :delete_all causes all the associated objects to be deleted directly from the database preventing any callbacks from being executed.

When we have a large system with multiple layered hierarchies of associated objects, cascading deletes might fail. A model could have associations that are destroyed which in turn trigger other deletions and this can continue down a complex tree. Such cascading deletes could turn out to be quite time consuming and might be rolled back in case of a server timeout error.

Solution? :destroy_async

Rails 6.1 now allows associations supporting the dependent: key to take :destroy_async as a value.

Example:

Suppose we have an Author model and a Book model.

Notice that we are passing :destroy_async as a value to the dependent option of has_many :books association:

class Author < ApplicationRecord
  has_many :books, dependent: :destroy_async
end
class Book < ApplicationRecord
  belongs_to :author
end

Say we destroy the author with an id of 1 who had 4 associated books with ids 1, 2, 3, 4, we see that Rails enqueues a job -

Performing ActiveRecord::DestroyAssociationAsyncJob (Job ID: 40d5c0cf-ed73-493b-8964-541ae6f1960f) from Async(active_record_destroy) enqueued at 2020-11-16T15:27:00Z with arguments: {:owner_model_name=>"Author", :owner_id=>1, :association_class=>"Book", :association_ids=>[1, 2, 3, 4], :association_primary_key_column=>:id,

The Author record is deleted from our database and we see the following log-

Performed ActiveRecord::DestroyAssociationAsyncJob (Job ID: 40d5c0cf-ed73-493b-8964-541ae6f1960f) from Async(active_record_destroy) in 21.8ms