Perbedaan antara Hancurkan dan Hapus

210

Apa perbedaan antara

@model.destroy dan @model.delete

Sebagai contoh:

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

Apakah penting jika saya menggunakan yang satu atau yang lain?

Saggex
sumber

Jawaban:

289

Pada dasarnya destroymenjalankan semua callback pada model sementara deletetidak.

Dari API Rails :

  • ActiveRecord::Persistence.delete

    Menghapus catatan dalam database dan membekukan instance ini untuk mencerminkan bahwa tidak ada perubahan yang harus dilakukan (karena tidak dapat dipertahankan). Mengembalikan contoh beku.

    Baris hanya dihapus dengan pernyataan SQL DELETE pada kunci utama catatan, dan tidak ada panggilan balik yang dijalankan.

    Untuk menegakkan callback sebelum_destroy dan after_destroy objek atau apa pun: opsi asosiasi yang bergantung, gunakan #destroy.

  • ActiveRecord::Persistence.destroy

    Menghapus catatan dalam database dan membekukan instance ini untuk mencerminkan bahwa tidak ada perubahan yang harus dilakukan (karena tidak dapat dipertahankan).

    Ada serangkaian panggilan balik yang terkait dengan penghancuran. Jika panggilan balik before_destroy kembali palsu tindakan dibatalkan dan menghancurkan kembali palsu. Lihat ActiveRecord :: Callbacks untuk detail lebih lanjut.

Komunitas
sumber
Halo @ user740584 - terima kasih atas jawaban Anda. Apa yang Anda maksud dengan "menjalankan callback pada model"?
BKSpurgeon
3
@BKSpurgeon maksudnya ActiveRecord :: Callbacks: api.rubyonrails.org/classes/ActiveRecord/Callbacks.html . Salah satu panggilan balik tersebut adalah model#before_destroyyang dapat digunakan untuk menghentikan destroy()panggilan terakhir dalam kondisi tertentu.
Todd
102

delete hanya akan menghapus catatan objek saat ini dari db tetapi tidak terkait dengan catatan anak-anak dari db.

destroy akan menghapus catatan objek saat ini dari db dan juga catatan anak-anak terkait dari db.

Penggunaannya sangat penting:

Jika beberapa objek orang tua Anda membagikan objek anak-anak biasa, maka memanggil destroyobjek induk tertentu akan menghapus objek anak-anak yang dibagikan di antara banyak orang tua lainnya.

Taimoor Changaiz
sumber
5
Jawaban yang brilian. Terima kasih. Saya akan menambahkan bahwa terminologi seperti yang saya mengerti adalah bahwa anak-anak "terbunuh". pembunuhan bayi yang brutal.
BKSpurgeon
Dalam kebanyakan kasus dalam produksi, Anda ingin menggunakan 'hancurkan'
Outside_Box
Tidak, ini tidak perlu.
Taimoor Changaiz
Saya pikir kata yang harus Anda gunakan destroyadalah keturunan , bukan anak - anak : menurut dokumentasi, menghancurkan "menciptakan objek baru dari atribut, dan kemudian memanggil menghancurkan di atasnya." rubydoc.info/docs/rails/4.1.7/ActiveRecord%2Felation:destroy
Marco Lackovic
12

Ketika Anda memohon destroyatau destroy_allpada suatu ActiveRecordobjek, proses ActiveRecord'penghancuran' dimulai, ia menganalisis kelas yang Anda hapus, itu menentukan apa yang harus dilakukan untuk dependensi, dijalankan melalui validasi, dll.

Ketika Anda memohon deleteatau delete_allpada suatu objek, ActiveRecordhanya mencoba menjalankan DELETE FROM tablename WHERE conditionskueri terhadap db, tidak melakukan ActiveRecordtugas tingkat- lain .

nickcen
sumber
4

Ya ada perbedaan besar antara kedua metode. Gunakan delete_all jika Anda ingin catatan dihapus dengan cepat tanpa model panggilan balik dipanggil

Jika Anda peduli dengan model Anda, callback kemudian gunakan destroy_all

Dari dokumen resmi

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

destroy_all (kondisi = nil) publik

Hancurkan kondisi pencocokan catatan dengan membuat instance setiap catatan dan memanggil metode penghancurannya. Setiap panggilan balik objek dieksekusi (termasuk: opsi asosiasi dependen dan metode before_destroy / after_destroy Observer). Mengembalikan koleksi benda yang dihancurkan; masing-masing akan dibekukan, untuk mencerminkan bahwa tidak ada perubahan yang harus dilakukan (karena tidak dapat dipertahankan).

Catatan: Instansiasi, eksekusi panggilan balik, dan penghapusan setiap catatan bisa memakan waktu ketika Anda menghapus banyak catatan sekaligus. Ini menghasilkan setidaknya satu query SQL DELETE per record (atau mungkin lebih, untuk menegakkan callback Anda). Jika Anda ingin menghapus banyak baris dengan cepat, tanpa memperhatikan asosiasi atau panggilan baliknya, gunakan delete_all sebagai gantinya.

jamesc
sumber
2

Pada dasarnya "delete" mengirimkan permintaan langsung ke database untuk menghapus catatan. Dalam hal itu Rails tidak tahu atribut apa yang ada dalam catatan itu dihapus atau apakah ada panggilan balik (seperti before_destroy).

Metode "hancurkan" mengambil id yang lewat, mengambil model dari database menggunakan metode "temukan", kemudian panggilan hancurkan pada itu. Ini berarti callback terpicu.

Anda ingin menggunakan "hapus" jika Anda tidak ingin callback terpicu atau Anda menginginkan kinerja yang lebih baik. Kalau tidak (dan sebagian besar waktu) Anda akan ingin menggunakan "menghancurkan".

Severin
sumber
2

Sudah banyak jawaban; ingin melompat dengan sedikit lebih banyak.

dokumen :

Untuk has_many, hancurkan dan hancurkan_all akan selalu memanggil metode hancurkan dari catatan yang dihapus sehingga callback dijalankan. Namun delete dan delete_all akan melakukan penghapusan sesuai dengan strategi yang ditentukan oleh opsi: dependen, atau jika tidak ada: dependen diberikan, maka ia akan mengikuti strategi default. Strategi default adalah tidak melakukan apa-apa (biarkan kunci asing dengan set induk ids ditetapkan), kecuali untuk has_many: through, di mana strategi default adalah delete_all (hapus catatan bergabung, tanpa menjalankan callback mereka).

The deleteverbage bekerja secara berbeda untuk ActiveRecord::Association.has_manydan ActiveRecord::Base. Untuk yang terakhir, hapus akan mengeksekusi SQL DELETEdan memotong semua validasi / panggilan balik. Yang pertama akan dieksekusi berdasarkan :dependentopsi yang diteruskan ke asosiasi. Namun, selama pengujian, saya menemukan efek samping berikut di mana callback hanya dijalankan untuk deletedan tidakdelete_all

dependent: :destroy Contoh:

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]]
David Zhang
sumber