web-dev-qa-db-ja.com

破棄と削除の違い

違いは何ですか

@model.destroy@model.delete

例えば:

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

どちらを使用しても問題ありませんか。

177
user3383458

基本的にdestroyはモデルに対してコールバックを実行しますが、deleteは実行しません。

Rails APIから

  • ActiveRecord::Persistence.delete

    データベース内のレコードを削除し、このインスタンスをフリーズして、変更を加えないようにします(永続化できないため)。フリーズしたインスタンスを返します。

    レコードの主キーに対するSQL DELETEステートメントを使用して行が単純に削除され、コールバックは実行されません。

    オブジェクトのbefore_destroyおよびafter_destroyコールバック、またはany:依存関係オプションを強制するには#destroyを使用してください。

  • ActiveRecord::Persistence.destroy

    データベース内のレコードを削除し、このインスタンスをフリーズして、変更を加えないようにします(永続化できないため)。

    Destroyに関連した一連のコールバックがあります。 before_destroyコールバックがfalseを返すと、アクションはキャンセルされ、destroyはfalseを返します。詳しくはActiveRecord :: Callbacksを見てください。

252
user740584

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

destroyは、現在のオブジェクトレコードをdbから削除し、それに関連付けられた子レコードもdbから削除します。

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

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

88

destroyオブジェクトに対してActiveRecordまたはdestroy_allを呼び出すと、ActiveRecordの「破棄」プロセスが開始され、削除するクラスが分析され、依存関係に対して実行する必要がある処理が決定され、検証が実行されます。

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

11
nickcen

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

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

公式文書より

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

destroy_all(条件=なし)public

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

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

4
jamesc

基本的に "delete"はレコードを削除するためにクエリを直接データベースに送ります。その場合、Railsはそれが削除しているレコードにどんな属性があるのか​​、あるいはコールバック(before_destroyのような)があるのか​​どうかを知りません。

"destroy"メソッドは渡されたidを受け取り、 "find"メソッドを使ってデータベースからモデルを取得し、それからdestroyを呼び出します。これはコールバックが引き起こされることを意味します。

コールバックをトリガーしたくない場合やパフォーマンスを向上させたい場合は、 "delete"を使用します。そうでなければ(そしてほとんどの場合)、あなたは "destroy"を使いたくなるでしょう。

2
Severin

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

docs

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

deleteヴェルベッジは、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]]
0
David Zhang