web-dev-qa-db-ja.com

delete_all vs destroy_all?

テーブルからレコードを削除する最良の方法を探しています。たとえば、ユーザー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関数を呼び出すことがわかりましたが、正しいアプローチを確認したいだけです。

179
glogic

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

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

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

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

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

21
Ryan Her

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

16
simon-olivier

small gem を作成しました。これにより、状況によっては関連するレコードを手動で削除する必要性を軽減できます。

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

依存::delete_recursively

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

Dependent::deleteまたはdependent::delete_allと同様に、この新しいオプションは依存レコードのaround/before/after_destroyコールバックをトリガーしないことに注意してください。

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

1
Janosch