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、他のすべてのテーブルからはnullになりますが、レコードはそのまま残ります。このようなタスクを実行するための正しいプロセスを誰かが共有できますか?

関連するすべてのオブジェクトで関数がdestroy_all呼び出されるのがわかりdestroyますが、正しいアプローチを確認したいだけです。

回答:


243

あなたが正しいです。ユーザーとすべての関連オブジェクトdestroy_all を削除する場合-> ただし、すべての関連オブジェクトを抑制せずにユーザーを削除する場合->delete_all

この投稿によると:Rails:dependent =>:destroy VS:dependent =>:delete_all

  • destroy/ destroy_all:関連するオブジェクトは、destroyメソッドを呼び出すことにより、このオブジェクトと一緒に破棄されます
  • delete/ delete_all:関連するすべてのオブジェクトは、:destroyメソッドを呼び出さずにすぐに破棄されます

80
1)の使用時にコールバックが呼び出されないことdelete_all、2)destroy_allすべてのレコードがインスタンス化されて一度に1つが破棄されることにも注意してください。非常に大きなデータセットを使用すると、非常に遅くなる可能性があります。
ディランマルコウ2011

モデルでbefore_destroyメソッドを実行しているとしましょう-delete_allを使用すると、このメソッドは実行されませんか?次に、モデルでbefore_deleteメソッドを使用している場合、これはRailsコンソールでdeleteまたはdelete_allを実行したときに実行されますか?
BKSpurgeon 2016年

23

delete_allは単一のSQL DELETEステートメントであり、それ以上のものはありません。destroy_allは、少なくともNUM_OF_RESULTS SQLステートメントである可能性がある:conditions(ある場合)の一致するすべての結果に対してdestroy()を呼び出します。

大きなデータセットに対してdestroy_all()などの抜本的な処理を行う必要がある場合、おそらくアプリからそれを行わず、手動で慎重に処理します。データセットが十分に小さければ、それほど害はありません。


16

destroy_allすべてのレコードをインスタンス化して一度に1つずつ破棄するという事実を回避するには、モデルクラスから直接使用できます。

だから代わりに:

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つのクエリです。


1
関連するレコードでdestroyコールバックを呼び出しますか、それともUsageIndex.destroy_all同等UsageIntex.delete_allですか?
マグネ

UsageIndex.destroy_allレール3以降は利用できなくなりました
fabriciofreitag

1

状況によっては、関連するレコードを手動で削除する必要性を軽減できる小さな宝石を作りました。

このgemは、ActiveRecordの関連付けのための新しいオプションを追加します:

dependent::delete_recursively

レコードを破棄すると、このオプションを使用して関連付けられているすべてのレコードは、インスタンス化せずに再帰的に(つまり、モデル間で)削除されます。

dependent::deleteまたはdependent::delete_allと同様に、この新しいオプションは、依存するレコードのaround / before / after_destroyコールバックをトリガーしません。

ただし、それ以外の場合はdependent::delete_recursivelyに関連付けられているモデルのチェーン内の任意の場所にdependent::destroy関連付けを設定することは可能です。:destroyオプションは、通常、行のどこでもどこでも機能し、関連するすべてのレコードをインスタンス化して破棄し、コールバックもトリガーします。


これは素晴らしいです!どうしてもっと多くの人がgithubでそれを観たり、スターを付けたり、フォークしたりしていないのでしょうか?それはまだうまくいきますか?
マグネ

@マグネありがとう!うまくいくはずです。テストはRuby 2.4.1およびRails 5.1.1で実行されます。これまでのところ、私はそれを非公開で使用しており、主要な製品アプリでは使用していないため、メジャーバージョンは「0」ですが、問題に気づくことはありません。それもかなり単純なので、問題ないはずです。
Janosch

涼しい。:) Ruby 2.3.1、「rails」、「〜> 4.1.14」でプロジェクトを実行していますが、他のgemが原因で、悲しいことにactiverecord(〜> 4.1.0)に依存せざるを得ません。delete_recursivelyが0.9.0に解決されていることがわかります。activerecord 4.1で動作する古いバージョンはありますか?githubのリリースタブには何も見つかりませんでした。
マグネ

1
@Magne 4.1.14までのActiveRecordで実際に機能することがわかり、依存関係が緩和されたGemバージョン1.0.0をリリースしました。ただし、Railsの4.1ブランチはセキュリティ更新を受信しないことに注意してください。
Janosch
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.