Rails 7.0 Added Batch Processing Of Records For destroy_all
July 03, 2021
In Ruby on Rails, we use
destroy_all when we want to delete a collection of
Article.where(published: false).destroy_all # Logs # Article Load (0.3ms) SELECT "articles".* FROM "articles" WHERE "articles"."published" = #? [["published", 0]] # TRANSACTION (0.1ms) begin transaction # Article Destroy (0.5ms) DELETE FROM "articles" WHERE "articles"."id" = ? [["id", 1]] # TRANSACTION (1.7ms) commit transaction # TRANSACTION (0.1ms) begin transaction # Article Destroy (0.5ms) DELETE FROM "articles" WHERE "articles"."id" = ? [["id", 2]] # TRANSACTION (1.9ms) commit transaction # Output #=> [#<Article id: 1, title: "#0 Title", published: false>, #<Article id: 2, title: "#1 Title", published: false">]
As we notice above in the logs, all the records were loaded into the memory at a time and then
DELETE transaction was initiated for each record one by one.
destroy_allalways returns the destroyed records as an array.
The initial load of all records at a time consumes memory unnecessarily which can be processed in batches.
Before Ruby on Rails 7.0, to destroy records in batches, we had to use
destroy_all methods defined in
Let's refactor above example to process it in batches:
# Ruby on Rails 6.1 Article.where(published: false).in_batches(of: 100).destroy_all
With Ruby on Rails 7.0, we do not have to use
in_batches under the hood and allows us to process records in batches.
Hence, we can update the above example as follows:
# Ruby on Rails 7.0 Article.where(published: false).destroy_all(batch_size: 100) # Output #=> nil
destroy_allin Ruby on Rails 7.0 returns
Since this change will break many existing applications,
we can add the following configuration to existing applications to keep using the old
Rails.application.config.active_record.destroy_all_in_batches = false
Applications migrating from older versions to Ruby on Rails 7.0 will find this configuration option in
However, this will give a deprecation warning as
destroy_all batch processing will become the default behaviour in Ruby on Rails 7.1 .
DEPRECATION WARNING: As of Rails 7.1, destroy_all will no longer return the collection of objects that were destroyed. To transition to the new behaviour set the following in an initializer: Rails.application.config.active_record.destroy_all_in_batches = true
destroy_all with batch processing optionally accepts the following arguments:
batch_size: If we do not provide any
1000is the default
finish: We can pass our targeted primary key range in
order: We can destroy records by ordering them using primary key either in
the default order is
error_on_ignore: We can override the application level
Here is the link to the pull request.