破棄と削除の違い


210

違いは何ですか

@model.destroy そして @model.delete

例えば:

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

どちらを使用するかは本当に重要ですか?

回答:


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 2016年

3
@BKSpurgeon彼はActiveRecordの::コールバックを意味しますapi.rubyonrails.org/classes/ActiveRecord/Callbacks.html。そのようなコールバックの1つは、特定の条件下でmodel#before_destroy最終的なdestroy()呼び出しを停止するために使用できるコールバックです。
トッド

102

delete dbから現在のオブジェクトレコードを削除するだけで、関連する子レコードはdbから削除しません。

destroy 現在のオブジェクトレコードをdbから削除し、関連する子レコードもdbから削除します。

それらの使用は本当に重要です:

複数の親オブジェクトが共通の子オブジェクトを共有している場合、destroy特定の親オブジェクトを呼び出すと、他の複数の親の間で共有されている子オブジェクトが削除されます。


5
素晴らしい答え。ありがとうございました。子供たちが「殺された」ということを理解しているので、この用語を付け加えます。残忍な幼児殺し。
BKSpurgeon 2016年

ほとんどの場合、本番環境では「破棄」を使用したい
Outside_Box

いいえ、これは必要ありません。
Taimoor Changaiz

私はあなたのために使用されなければならない単語が考えるdestroyある子孫ではなく、子供のドキュメントによると、破壊する「属性から新しいオブジェクトを作成し、それを破壊する呼び出します。」:rubydoc.info/docs/rails/4.1.7/ActiveRecord%2FRelation:destroy
Marco Lackovic

12

オブジェクトを呼び出すとき、destroyまたはオブジェクトに対して、「破壊」プロセスが開始され、削除するクラスを分析し、依存関係に対して何をすべきかを決定し、検証を実行します。destroy_allActiveRecordActiveRecord

オブジェクトを呼び出すとき、deleteまたはdelete_allオブジェクトに対して、はデータベースに対してクエリActiveRecordを実行しようとするだけDELETE FROM tablename WHERE conditionsで、他のActiveRecordレベルのタスクは実行しません。


4

はい、2つの方法には大きな違いがあります。モデルコールバックを呼び出さずにレコードをすばやく削除する場合は、delete_allを使用します。

モデルのコールバックを気にする場合は、destroy_allを使用してください。

公式ドキュメントから

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

destroy_all(conditions = nil)public

各レコードをインスタンス化してdestroyメソッドを呼び出すことにより、条件に一致するレコードを破棄します。各オブジェクトのコールバックが実行されます(:依存関係オプションとbefore_destroy / after_destroy Observerメソッドを含む)。破棄されたオブジェクトのコレクションを返します。(永続化できないため)変更を加えてはならないことを反映して、それぞれがフリーズされます。

注:一度に多くのレコードを削除する場合、インスタンス化、コールバックの実行、および各レコードの削除には時間がかかる場合があります。レコードごとに少なくとも1つのSQL DELETEクエリを生成します(コールバックを強制するために、場合によってはそれ以上)。関連付けやコールバックを考慮せずに多数の行をすばやく削除する場合は、代わりにdelete_allを使用します。


2

基本的に「削除」は、クエリをデータベースに直接送信して、レコードを削除します。その場合、Railsは、削除するレコードにどの属性があるのか​​、またはコールバック(before_destroy)。

"destroy"メソッドは渡されたIDを取得し、 "find"メソッドを使用してデータベースからモデルをフェッチしてから、それに対してdestroyを呼び出します。つまり、コールバックがトリガーされます。

コールバックがトリガーされないようにする場合、またはパフォーマンスを向上させる場合は、「削除」を使用します。それ以外の場合(およびほとんどの場合)、「破棄」を使用する必要があります。


2

すでに多くの答えがあります。もう少しジャンプしたかった。

docs

has_manyの場合、destroyおよびdestroy_allは常に、削除されるレコードのdestroyメソッドを呼び出し、コールバックが実行されるようにします。ただし、deleteとdelete_allは、:dependentオプションで指定された方法に従って削除を行うか、:dependentオプションが指定されていない場合は、デフォルトの方法に従います。デフォルトの戦略は何もしないことです(外部キーは親IDを設定したままにします)。ただし、has_many:throughを除き、デフォルトの戦略はdelete_all(コールバックを実行せずに結合レコードを削除)です。

deleteverbageはのために動作が異なりますActiveRecord::Association.has_manyActiveRecord::Base。後者の場合、deleteが実行され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]]
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.