2011-07-14 35 views
150

我正在尋找從表中刪除記錄的最佳方法。例如,我有一個用戶的用戶ID跨越很多表。我想刪除此用戶以及所有表中具有其ID的每個記錄。delete_all vs destroy_all?

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函數,但我只是想確認正確的方法。

回答

187

你說得對。如果你想刪除的用戶和所有相關的對象 - >destroy_all 但是,如果你只是想刪除的用戶,但不影響所有相關的對象 - >delete_all

根據這個帖子:Rails :dependent => :destroy VS :dependent => :delete_all

  • destroy/destroy_all:通過調用其銷燬方法將關聯對象與此對象一起銷燬
  • delete/delete_all:所有關聯的對象都會立即銷燬,而不會調用它們:destroy方法
+61

還應該注意的是:1)使用'delete_all'時不調用回調函數,2)'destroy_all'實例化所有記錄並一次銷燬一個記錄,所以對於一個非常大的數據集,會痛苦地慢。 –

+0

假設我在模型中運行before_destroy方法 - 如果我使用delete_all,那麼此方法將不會運行?其次,如果我在我的模型中使用before_delete方法,當我在rails控制檯中運行delete或delete_all時,會運行嗎? – BKSpurgeon

19

delete_all是一個單獨的SQL DELETE語句,僅此而已。 destroy_all調用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}" 

結果是一個查詢消滅所有的相關記錄

+0

它會調用相關記錄的銷燬回調,還是'UsageIndex.destroy_all'等同於'UsageIntex.delete_all'? – Magne

1

我做了一個small gem,可以緩解在某些情況下需要手動刪除相關記錄。

這種寶石增加了ActiveRecord關聯的一個新的選擇:

依賴:delete_recursively

當你摧毀的記錄,正在使用該選項相關聯的所有記錄都將被遞歸刪除(即跨模型),而沒有實例化它們中的任何一個。

請注意,就像dependent::delete或dependent::delete_all一樣,此新選項不會觸發依賴記錄的around/before/after_destroy回調。

但是,可能有依賴關係::在與依賴關係:: delete_recursively相關聯的模型鏈中的任意位置釋放關聯。 The destroy選項可以正常工作在任何位置,上下線,實例化和銷燬所有相關記錄,從而也觸發回調。

+0

這太棒了!我想知道爲什麼沒有更多的人在github上觀看/主演/分發它。它仍然運行良好嗎? – Magne

+0

@Magne謝謝!它應該工作。測試在Ruby 2.4.1和Rails 5.1.1上運行。到目前爲止,我只是私下使用它,而不是主要的生產應用程序,因此主要版本爲「0」,但我從未發現任何問題。這也相當簡單,所以它應該沒問題。 – Janosch

+0

很酷。 :)我正在運行一個Ruby 2.3.1和'rails','〜> 4.1.14'的項目,並且由於其他寶石,我不得不依賴activerecord(〜> 4.1.0)。我看到delete_recursively已解析爲0.9.0。是否有一個與activerecord 4.1兼容的舊版本?我在github的發佈標籤中找不到任何內容。 – Magne