delete_all与destroy_all?


192

我正在寻找从表中删除记录的最佳方法。例如,我有一个用户,其用户ID跨多个表。我想删除该用户以及所有表中具有其ID的每条记录。

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函数,但我只想确认正确的方法。

Answers:


242

你是对的。如果要删除用户和所有关联的对象-> destroy_all 但是,如果只想删除用户而不隐藏所有关联的对象->delete_all

根据这篇文章:Rails:depend =>:destroy VS:depend =>:delete_all

  • destroy/ destroy_all:通过调用它们的destroy方法,与此对象一起销毁相关对象
  • delete/ delete_all:所有关联的对象将立即销毁,而无需调用它们的:destroy方法

80
还应注意的是:1)使用时不调用回调delete_all,并且2)destroy_all实例化所有记录并一次销毁一条记录,因此对于非常大的数据集,这可能会非常缓慢。
Dylan Markow

假设我在模型中运行before_destroy方法-如果我使用delete_all,则此方法将无法运行?其次,如果我在模型中采用了before_delete方法,当我在rails控制台中运行delete或delete_all时,是否可以运行此方法?
BKSpurgeon

23

delete_all是单个SQL DELETE语句,仅此而已。destroy_all对:conditions的所有匹配结果(如果有的话)都调用destroy(),该结果可能至少为NUM_OF_RESULTS条SQL语句。

如果您必须在大型数据集上执行诸如destroy_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
它会在关联记录上调用destroy回调,还是UsageIndex.destroy_all等效于UsageIntex.delete_all
Magne

UsageIndex.destroy_all由于rails 3
fabriciofreitag

1

我做了一个小宝石,可以减轻在某些情况下手动删除关联记录的需要。

此gem为ActiveRecord关联添加了一个新选项:

依赖::delete_recursively

销毁记录时,使用此选项关联的所有记录将被递归删除(即跨模型),而无需实例化任何记录。

请注意,就像dependent::delete或dependent::delete_all一样,此新选项不会触发依赖记录的around / before / after_destroy回调。

但是,有可能在模型链中的任何地方都具有dependent :: destroy关联,否则它们与dependent :: delete_recursively关联。:destroy选项将正常运行在行中的任何地方,实例化并销毁所有相关记录,并因此触发它们的回调。


这是太棒了!我想知道为什么没有更多的人在github上观看/加注星标/分叉它了..它仍然运行良好吗?
Magne

@Magne谢谢!它应该正在工作。测试在Ruby 2.4.1和Rails 5.1.1上运行。到目前为止,我只是私下使用它,而没有在主要的生产应用程序中使用它,因此主要版本是“ 0”,但是我从未注意到任何问题。这也很简单,所以应该没问题。
Janosch '17

凉。:)我正在Ruby 2.3.1和'rails','〜> 4.1.14'上运行一个项目,但由于其他原因,我不得不被迫依赖activerecord(〜> 4.1.0)。我看到delete_recursively解析为0.9.0。是否有适用于activerecord 4.1的旧版本?我在github的releases标签中找不到任何内容。
Magne

1
@Magne我发现它实际上适用于 ActiveRecords 低至4.1.14,并发布了带有宽松依赖的gem版本1.0.0。请记住,尽管如此,Rails的4.1分支不再接收安全更新。
Janosch '17
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.