Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ActiveRecord - Get the last n records and delete them in one command?

Hello all and thanks for taking the time to answer my question.

The question is really explained in the title.

I tried Model.last(n).destroy_all but none of that would work.

I was wondering if it is possible to do it in one line, and if not what would be the cleanest way of doing it?

Thanks again!

like image 620
Dragan Avatar asked Jan 15 '14 07:01

Dragan


People also ask

What are ActiveRecord methods?

Active Record allows you to validate the state of a model before it gets written into the database. There are several methods that you can use to check your models and validate that an attribute value is not empty, is unique and not already in the database, follows a specific format, and many more.

What does ActiveRecord base do?

ActiveRecord::Base indicates that the ActiveRecord class or module has a static inner class called Base that you're extending.

How do you delete a record in rails?

Rails delete operation using destroy method By using destroy, you can delete the record from rails as well as its other existing dependencies. So in the context of our rails application, if we delete a book record using the destroy function, the authors associated with the book will also be deleted.

Is ActiveRecord an ORM?

ActiveRecord is an ORM. It's a layer of Ruby code that runs between your database and your logic code.


2 Answers

To do it in one SQL query use delete_all:

Model.order(created_at: :desc).limit(n).delete_all

But delete_all won't execute any model callbacks or validations

To run callbacks and validations use destroy_all:

Model.order(created_at: :desc).limit(n).destroy_all

Unfortunately destroy_all will execute n + 1 SQL queries: 1 query to retrieve records and n queries to delete each record.

like image 91
Ivan Denysov Avatar answered Sep 18 '22 18:09

Ivan Denysov


You can achieve this by:

Model.last(n).each(&:destroy)

@IvanDenisov points out another way to do this:

Model.order('created_at DESC').limit(n).destroy_all

It's basically doing the same thing according to Rails API Doc, but a little bit verbose. Besides, it doesn't do all things in one SQL query.


Detailed comparison of SQL queries

I tried to run both codes in rails console under Ruby 2.0.0p253 && Rails 4.0.4, here are the results:

2.0.0p353 :002 > Role.last(3).each(&:destroy)
  Role Load (1.0ms)  SELECT "roles".* FROM "roles" ORDER BY "roles"."id" DESC LIMIT 3
   (0.3ms)  BEGIN
  SQL (3.5ms)  DELETE FROM "roles" WHERE "roles"."id" = $1  [["id", 5487]]
   (11.8ms)  COMMIT
   (0.1ms)  BEGIN
  SQL (0.2ms)  DELETE FROM "roles" WHERE "roles"."id" = $1  [["id", 5488]]
   (5.4ms)  COMMIT
   (0.1ms)  BEGIN
  SQL (0.2ms)  DELETE FROM "roles" WHERE "roles"."id" = $1  [["id", 5489]]
   (4.6ms)  COMMIT

2.0.0p353 :004 > Role.order('created_at DESC').limit(3).destroy_all
  Role Load (0.9ms)  SELECT "roles".* FROM "roles" ORDER BY created_at DESC LIMIT 3
   (0.2ms)  BEGIN
  SQL (0.2ms)  DELETE FROM "roles" WHERE "roles"."id" = $1  [["id", 5492]]
   (6.6ms)  COMMIT
   (0.2ms)  BEGIN
  SQL (0.2ms)  DELETE FROM "roles" WHERE "roles"."id" = $1  [["id", 5491]]
   (0.4ms)  COMMIT
   (0.1ms)  BEGIN
  SQL (0.1ms)  DELETE FROM "roles" WHERE "roles"."id" = $1  [["id", 5490]]
   (0.2ms)  COMMIT

The DELETE parts are exactly the same. They both took multiple SQL queries.

The only difference is SELECT part, if we change 'created_at DESC' to 'id DESC', they will be exactly the same too.

like image 26
Jun Zhou Avatar answered Sep 18 '22 18:09

Jun Zhou