销毁和删除之间的区别


210

之间有什么区别

@model.destroy@model.delete

例如:

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

如果我使用一个或另一个真的有关系吗?

Answers:


289

基本上destroy在模型上运行任何回调,而delete没有。

Rails API中

  • ActiveRecord::Persistence.delete

    删除数据库中的记录并冻结该实例以反映不应进行任何更改(因为它们不能持久保存)。返回冻结的实例。

    只需在记录的主键上使用SQL DELETE语句删除该行,就不会执行回调。

    要强制执行对象的before_destroy和after_destroy回调或任何:dependent关联选项,请使用#destroy。

  • ActiveRecord::Persistence.destroy

    删除数据库中的记录并冻结该实例以反映不应进行任何更改(因为它们不能持久保存)。

    有一系列与destroy相关的回调。如果before_destroy回调返回false,则取消操作,destroy返回false。有关更多详细信息,请参见ActiveRecord :: Callbacks。


您好@ user740584-感谢您的回答。“在模型上运行任何回调”是什么意思?
BKSpurgeon '16

3
@BKSpurgeon他的意思是ActiveRecord :: Callbacks:api.rubyonrails.org/classes/ActiveRecord/Callbacks.html。一种这样的回调是model#before_destroy可以用来destroy()在某些条件下终止最终调用的。
托德

102

delete 只会从db中删除当前对象记录,而不会从db中删除其相关的子记录。

destroy 将从db中删除当前对象记录,并从db中删除其相关的子记录。

它们的使用确实很重要:

如果您的多个父对象共享公共子对象,则调用destroy特定父对象将删除在其他多个父对象之间共享的子对象。


5
辉煌的答案。谢谢。我要补充一点,据我所知,这是儿童被“杀死”的原因。残酷的杀婴。
BKSpurgeon '16

在生产中的大多数情况下,您都想使用“销毁”功能
Outside_Box

不,这不是必需的。
Taimoor Changaiz

我认为您应该使用的单词destroy后代,而不是子代:根据文档,destroy“根据属性创建一个新对象,然后在其上调用destroy”。rubydoc.info/docs/rails/4.1.7/ActiveRecord%2FRelation:destroy
Marco Lackovic

12

当您调用对象destroydestroy_allActiveRecord对象上进行调用时,将ActiveRecord启动“销毁”过程,该过程将分析您要删除的类,确定对依赖项应执行的操作,并通过验证等操作。

在对象上调用deletedelete_all对对象进行调用时,ActiveRecord仅尝试DELETE FROM tablename WHERE conditions对db 运行查询,而不执行其他任何ActiveRecord级别的任务。


4

是的,这两种方法之间存在主要差异。如果要快速删除记录而不调用模型回调,请使用delete_all

如果您关心模型回调,请使用destroy_all

来自官方文档

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

destroy_all(conditions = nil)公共

通过实例化每个记录并调用其destroy方法来销毁匹配条件的记录。每个对象的回调都被执行(包括:dependent关联选项和before_destroy / after_destroy Observer方法)。返回被破坏的对象的集合;每个都将被冻结,以反映不应进行任何更改(因为它们无法持久保存)。

注意:一次删除许多记录时,实例化,回调执行和删除每个记录可能很耗时。它每条记录至少生成一个SQL DELETE查询(或者可能更多,以强制执行回调)。如果要快速删除许多行,而不用担心它们的关联或回调,请使用delete_all。


2

基本上,“删除”直接将查询发送到数据库以删除记录。在这种情况下,Rails不知道要删除的记录中包含哪些属性,也不知道是否有任何回调(例如before_destroy)。

“ destroy”方法采用传递的id,然后使用“ find”方法从数据库中获取模型,然后对其进行调用destroy。这意味着回调被触发。

如果您不希望触发回调或希望获得更好的性能,则可以使用“删除”。否则(大部分时间),您将要使用“销毁”。


2

已经有很多答案;想多跳一点。

docs

对于has_many,destroy和destroy_all将始终调用要删除的记录的destroy方法,以便运行回调。但是delete和delete_all将根据:depend选项指定的策略进行删除,或者,如果未给出:dependent选项,则它将遵循默认策略。除了has_many:through以外,默认策略为不执行任何操作(保留设置了父ID的外键),默认策略为delete_all(删除联接记录,而不运行其回调)。

delete对于ActiveRecord::Association.has_many和来说,语言的用法不同ActiveRecord::Base。对于后者,删除将执行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]]
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.