delete_all vs kill_all?


193

Я шукаю найкращий підхід для видалення записів із таблиці. Наприклад, у мене є користувач, чий ідентифікатор користувача знаходиться в багатьох таблицях. Я хочу видалити цього користувача та кожну запис, який має його ідентифікатор у всіх таблицях.

u = User.find_by_name('JohnBoy')
u.usage_indexes.destroy_all
u.sources.destroy_all
u.user_stats.destroy_all
u.delete

Це працює і видаляє всі посилання користувача з усіх таблиць, але я чув, що це destroy_allбуло дуже важко, тому я спробував delete_all. Він видаляє користувача лише з його власної таблиці користувачів, а idз усіх інших таблиць стає недійсним, але залишає записи недоторканими в них. Чи може хтось поділитися, що правильний процес для виконання такого завдання?

Я бачу, що destroy_allвикликає destroyфункцію на всіх пов'язаних об'єктах, але я просто хочу підтвердити правильний підхід.

Відповіді:


244

Ти правий. Якщо ви хочете видалити Користувача та всі пов’язані з ним об’єкти -> destroy_all Однак, якщо ви просто хочете видалити Користувача без придушення всіх пов’язаних об'єктів ->delete_all

Відповідно до цього допису: Rails: залежно =>: знищити VS: залежно =>: delete_all

  • destroy/ destroy_all: Асоційовані об'єкти знищуються поряд з цим об'єктом, викликаючи метод їх знищення
  • delete/ delete_all: Усі асоційовані об'єкти знищуються негайно, не викликаючи їх метод: знищити

80
Слід також зазначити, що 1) Зворотні виклики не використовуються при використанні delete_all; 2) destroy_allстворюють усі записи та знищують їх по черзі, тому при дуже великому наборі даних це може бути болісно повільним.
Ділан Марков

припустимо, що я використовую метод model_dstroy в моделі - якщо я використовую delete_all, то цей метод не запуститься? по-друге, якщо у моїй моделі я використовуватиме метод методу before_delete, чи буде це запускатись, коли я запускаю delete або delete_all на консолі рейки?
BKSpurgeon

23

delete_all - це єдиний оператор SQL DELETE і більше нічого. знищити_all виклики знищити () на всіх результатах, що відповідають: умовам (якщо у вас є), які можуть бути принаймні NUM_OF_RESULTS SQL висловлювання.

Якщо вам доведеться зробити щось кардинальне, таке як kill_all () на великому наборі даних, я, мабуть, не зроблю це з програми та обробляйте його вручну обережно. Якщо набір даних досить малий, ви б не зашкодили так сильно.


16

Щоб уникнути того, що destroy_allекземпляри всіх записів та знищення їх по черзі, ви можете використовувати їх безпосередньо з модельного класу.

Тож замість:

u = User.find_by_name('JohnBoy')
u.usage_indexes.destroy_all

Ви можете зробити :

u = User.find_by_name('JohnBoy')
UsageIndex.destroy_all "user_id = #{u.id}"

Результат - один запит на знищення всіх пов'язаних записів


1
Чи буде він викликати зворотний виклик знищення на пов'язаних записах, або UsageIndex.destroy_allеквівалентний UsageIntex.delete_all?
Магне

UsageIndex.destroy_allбільше не доступний, оскільки рейки 3
fabriciofreitag

1

Я створив невеликий дорогоцінний камінь, який може полегшити необхідність видалення пов'язаних записів вручну за деяких обставин.

Цей самоцвіт додає нову опцію для асоціацій ActiveRecord:

залежно:: видалити_рекурсивно

Коли ви знищуєте запис, усі записи, пов’язані за допомогою цієї опції, будуть видалятися рекурсивно (тобто для моделей), без інстанції жодної з них.

Зауважте, що так само, як і залежне:: delete або залежно:: delete_all, ця нова опція не викликає зворотні виклики навколо / до / після_забезпечення залежних записів.

Однак можна мати залежне:: знищувати асоціації в будь-якій точці ланцюга моделей, які в іншому випадку асоціюються з залежними:: delete_recursively. Опція "знищити" буде працювати нормально в будь-якому місці вгору або вниз по лінії, створюючи екземпляри та знищуючи всі відповідні записи, і, таким чином, також викликаючи їх зворотні виклики.


Це фантастично! Цікаво, чому більше людей не дивилися / зіграли / розщедрили його на github .. це все ще добре працює?
Магне

@Magne Спасибі! Це повинно працювати. Тести виконуються на Ruby 2.4.1 та Rails 5.1.1. Поки я використовував його лише приватно, а не в основних виробничих додатках, отже, в основній версії "0", але я жодного разу не помітив жодних проблем. Це також досить просто, тому воно повинно бути добре.
Янош

Класно. :) Я працюю над проектом на Ruby 2.3.1 і 'rails', '~> 4.1.14', і, на жаль, змушений покладатися на activerecord (~> 4.1.0) через інші дорогоцінні камені. Я бачу, що delete_recursively дозволено до 0,9,0. Чи є його старша версія, яка б працювала з activerecord 4.1? На вкладці випусків на github я не зміг знайти жодного.
Магне

1
@Magne Я виявив, що насправді він працює на activerecord аж до 4.1.14 і випустив дорогоцінну версію 1.0.0 з послабленою залежністю. Майте на увазі, що 4.1 відділення Rails більше не отримує оновлення безпеки.
Янош
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.