Разница между уничтожением и удалением


210

В чем разница между

@model.destroy и @model.delete

Например:

Model.find_by(col: "foo").destroy_all
//and
Model.find_by(col: "foo").delete_all

Действительно ли имеет значение, использую ли я одно или другое?

Ответы:


289

В основном destroyзапускает любые обратные вызовы для модели, а deleteне делает.

Из Rails API :

  • ActiveRecord::Persistence.delete

    Удаляет запись в базе данных и замораживает этот экземпляр, чтобы отразить, что не следует вносить изменения (так как они не могут быть сохранены). Возвращает замороженный экземпляр.

    Строка просто удаляется с помощью оператора SQL DELETE для первичного ключа записи, и обратные вызовы не выполняются.

    Чтобы обеспечить обратные вызовы объекта before_destroy и after_destroy или любые: зависимые параметры ассоциации, используйте #destroy.

  • ActiveRecord::Persistence.destroy

    Удаляет запись в базе данных и замораживает этот экземпляр, чтобы отразить, что не следует вносить изменения (так как они не могут быть сохранены).

    Существует ряд обратных вызовов, связанных с уничтожением. Если обратный вызов before_destroy возвращает false, действие отменяется, а destroy возвращает false. См. ActiveRecord :: Callbacks для получения дополнительной информации.


Здравствуйте @ user740584 - спасибо за ваш ответ. Что вы подразумеваете под "запускает какие-либо обратные вызовы на модель"?
BKSpurgeon

3
@BKSpurgeon он имеет в виду ActiveRecord :: Callbacks: api.rubyonrails.org/classes/ActiveRecord/Callbacks.html . Одним из таких обратных вызовов является то, model#before_destroyчто может использоваться для остановки окончательного destroy()вызова при определенных условиях.
Тодд

102

delete удалит только текущую запись объекта из БД, но не связанные с ней дочерние записи из БД.

destroy удалит текущую запись объекта из базы данных, а также связанную с ней дочернюю запись из базы данных.

Их использование действительно имеет значение:

Если ваши родительские объекты имеют общие дочерние объекты, то вызов destroyопределенного родительского объекта приведет к удалению дочерних объектов, которые совместно используются другими несколькими родителями.


5
Блестящий ответ. Спасибо. я бы добавил, что терминология, как я понимаю, заключается в том, что дети «убиты». жестокий детоубийство.
BKSpurgeon

В большинстве случаев в производстве вы хотите использовать «уничтожить»
Outside_Box

Нет, это не обязательно.
Таймур Чангайз

Я думаю, что слово, которое вы должны использовать, destroyэто потомки , а не дети : согласно документации, destroy «создает новый объект из атрибутов, а затем вызывает для него уничтожение». rubydoc.info/docs/rails/4.1.7/ActiveRecord%2FRelation:destroy
Марко Лацкович

12

Когда вы вызываете destroyили destroy_allна ActiveRecordобъекте,ActiveRecord инициируется процесс «уничтожения», он анализирует класс, который вы удаляете, определяет, что он должен делать для зависимостей, проходит проверки и т. Д.

Когда вы вызываете объект deleteили обращаетесь delete_allк нему, он ActiveRecordпросто пытается выполнить DELETE FROM tablename WHERE conditionsзапрос к базе данных, не выполняя никаких других ActiveRecordзадач.


4

Да, между этими двумя методами есть существенное различие. Используйте delete_all, если хотите, чтобы записи быстро удалялись без вызова обратных вызовов модели.

Если вам небезразличны обратные вызовы ваших моделей, тогда используйте destroy_all

Из официальных документов

http://apidock.com/rails/ActiveRecord/Base/destroy_all/class

destroy_all (условие = ноль) публично

Уничтожает условия сопоставления записей, создавая каждую запись и вызывая ее метод уничтожения. Выполняются обратные вызовы каждого объекта (в том числе: зависимые параметры ассоциации и методы Observer before_destroy / after_destroy). Возвращает коллекцию объектов, которые были уничтожены; каждый будет заморожен, чтобы отразить, что никакие изменения не должны быть сделаны (так как их нельзя сохранить).

Примечание. Создание, обратный вызов и удаление каждой записи может занять много времени, если вы удаляете много записей одновременно. Он генерирует по крайней мере один запрос SQL DELETE для каждой записи (или, возможно, больше, для обеспечения ваших обратных вызовов). Если вы хотите быстро удалить много строк, не обращая внимания на их ассоциации или обратные вызовы, используйте вместо этого delete_all.


2

В основном «удалить» отправляет запрос непосредственно в базу данных, чтобы удалить запись. В этом случае Rails не знает, какие атрибуты находятся в записи, которую он удаляет, и нет ли каких-либо обратных вызовов (таких как before_destroy).

Метод "destroy" берет переданный идентификатор, выбирает модель из базы данных, используя метод "find", а затем вызывает destroy для этого. Это означает, что обратные вызовы запускаются.

Вы можете использовать «удалить», если не хотите, чтобы выполнялись обратные вызовы или вы хотите повысить производительность. В противном случае (и большую часть времени) вы захотите использовать «уничтожить».


2

Уже много ответов; хотел прыгнуть с немного больше.

документы :

Для has_many, destroy и destroy_all всегда будут вызывать метод уничтожения удаляемых записей, чтобы выполнялись обратные вызовы. Однако delete и delete_all будут выполнять удаление в соответствии со стратегией, указанной параметром: зависимый, или, если параметр не указан, то он будет следовать стратегии по умолчанию. Стратегия по умолчанию - ничего не делать (оставить внешние ключи с установленными родительскими идентификаторами), за исключением has_many: through, где стратегией по умолчанию является delete_all (удалить записи объединения, не выполняя их обратные вызовы).

deleteVerbage работает по- разному для ActiveRecord::Association.has_manyи ActiveRecord::Base. В последнем случае delete выполнит SQL DELETEи пропустит все проверки / обратные вызовы. Первый будет выполнен на основе :dependentопции, переданной в ассоциацию. Однако, во время тестирования, я нашел следующий побочный эффект , когда обратные вызовы пробежались только deleteи неdelete_all

dependent: :destroy Пример:

class Parent < ApplicationRecord
   has_many :children,
     before_remove: -> (_) { puts "before_remove callback" },
     dependent: :destroy
end

class Child < ApplicationRecord
   belongs_to :parent

   before_destroy -> { puts "before_destroy callback" }
end

> child.delete                            # Ran without callbacks
Child Destroy (99.6ms)  DELETE FROM "children" WHERE "children"."id" = $1  [["id", 21]]

> parent.children.delete(other_child)     # Ran with callbacks
before_remove callback
before_destroy callback
Child Destroy (0.4ms)  DELETE FROM "children" WHERE "children"."id" = $1  [["id", 22]]

> parent.children.delete_all              # Ran without callbacks
Child Destroy (1.0ms)  DELETE FROM "children" WHERE "children"."parent_id" = $1  [["parent_id", 1]]
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.