違いは何ですか
@model.destroy
と@model.delete
例えば:
Model.find_by(col: "foo").destroy_all
//and
Model.find_by(col: "foo").delete_all
どちらを使用しても問題ありませんか。
基本的にdestroy
はモデルに対してコールバックを実行しますが、delete
は実行しません。
ActiveRecord::Persistence.delete
データベース内のレコードを削除し、このインスタンスをフリーズして、変更を加えないようにします(永続化できないため)。フリーズしたインスタンスを返します。
レコードの主キーに対するSQL DELETEステートメントを使用して行が単純に削除され、コールバックは実行されません。
オブジェクトのbefore_destroyおよびafter_destroyコールバック、またはany:依存関係オプションを強制するには#destroyを使用してください。
ActiveRecord::Persistence.destroy
データベース内のレコードを削除し、このインスタンスをフリーズして、変更を加えないようにします(永続化できないため)。
Destroyに関連した一連のコールバックがあります。 before_destroyコールバックがfalseを返すと、アクションはキャンセルされ、destroyはfalseを返します。詳しくはActiveRecord :: Callbacksを見てください。
delete
は、現在のオブジェクトレコードをdbから削除するだけで、関連付けられている子レコードをdbから削除することはしません。
destroy
は、現在のオブジェクトレコードをdbから削除し、それに関連付けられた子レコードもdbから削除します。
それらの使用は本当に重要です。
複数の親オブジェクトが共通の子オブジェクトを共有している場合、特定の親オブジェクトでdestroy
を呼び出すと、他の複数の親の間で共有されている子オブジェクトが削除されます。
destroy
オブジェクトに対してActiveRecord
またはdestroy_all
を呼び出すと、ActiveRecord
の「破棄」プロセスが開始され、削除するクラスが分析され、依存関係に対して実行する必要がある処理が決定され、検証が実行されます。
オブジェクトに対してdelete
またはdelete_all
を呼び出すと、ActiveRecord
はdbに対してDELETE FROM tablename WHERE conditions
クエリを実行しようとするだけで、他のActiveRecord
レベルのタスクは実行されません。
はい、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を使用してください。
基本的に "delete"はレコードを削除するためにクエリを直接データベースに送ります。その場合、Railsはそれが削除しているレコードにどんな属性があるのか、あるいはコールバック(before_destroy
のような)があるのかどうかを知りません。
"destroy"メソッドは渡されたidを受け取り、 "find"メソッドを使ってデータベースからモデルを取得し、それからdestroyを呼び出します。これはコールバックが引き起こされることを意味します。
コールバックをトリガーしたくない場合やパフォーマンスを向上させたい場合は、 "delete"を使用します。そうでなければ(そしてほとんどの場合)、あなたは "destroy"を使いたくなるでしょう。
すでにたくさんの答えがあります。もう少しでジャンプしたかった。
docs :
Has_manyの場合、destroyとdestroy_allは常に削除されるレコードのdestroyメソッドを呼び出して、コールバックが実行されるようにします。しかしdeleteとdelete_allは:dependentオプションで指定された戦略に従って削除するか、あるいは:dependentオプションが与えられていなければデフォルトの戦略に従います。デフォルトの戦略は、デフォルトの戦略がdelete_all(コールバックを実行せずに結合レコードを削除する)であるhas_many:throughを除いて、何もしない(親IDを設定した外部キーを残す)ことです。
delete
ヴェルベッジは、ActiveRecord::Association.has_many
とActiveRecord::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]]