ActiveRecord - получить последние n записей и удалить их в одной команде?

Привет всем и спасибо за то, что нашли время, чтобы ответить на мой вопрос.

Вопрос действительно объясняется в заголовке.

Я попробовал Model.last(n).destroy_all, но ничего из этого не получилось.

Мне было интересно, можно ли сделать это в одной строке, а если нет, то какой будет самый чистый способ сделать это?

Еще раз спасибо!

Ответ 1

это удалит последние n записей в одном запросе sql

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

UPDATE: Более эффективным способом будет:

ids = Model.order('created_at DESC').limit(n).pluck(:id)
Model.where(id: ids).delete_all

Хотя это не одна команда, она выполняет только 2 SQL-запроса

Ответ 2

Вы можете достичь этого:

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

@ИванДенисов указывает еще один способ сделать это:

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

В основном он делает то же самое в соответствии с Rails API Doc, но немного подробный. Кроме того, он не делает все в одном запросе SQL.


Подробное сравнение SQL-запросов

Я попытался запустить оба кода в rails console под Ruby 2.0.0p253 && & Rails 4.0.4, вот результаты:

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

Части DELETE точно такие же. Они оба выполнили несколько SQL-запросов.

Единственное отличие - это SELECT part, если мы изменим 'created_at DESC' на 'id DESC', они будут точно такими же.