Differenza tra Distruggi ed Elimina


210

Qual è la differenza tra

@model.destroy e @model.delete

Per esempio:

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

Importa davvero se uso l'uno o l'altro?

Risposte:


289

Fondamentalmente destroyesegue tutti i callback sul modello mentre deletenon lo fa.

Dalla API Rails :

  • ActiveRecord::Persistence.delete

    Elimina il record nel database e blocca questa istanza per riflettere che non è necessario apportare modifiche (poiché non possono essere mantenute). Restituisce l'istanza congelata.

    La riga viene semplicemente rimossa con un'istruzione DELETE SQL sulla chiave primaria del record e non vengono eseguiti callback.

    Per forzare l'oggetto before_destroy e after_destroy callbacks o qualunque: opzione di associazione dipendente, usa #destroy.

  • ActiveRecord::Persistence.destroy

    Elimina il record nel database e blocca questa istanza per riflettere che non è necessario apportare modifiche (poiché non possono essere mantenute).

    C'è una serie di callback associati a distruggere. Se before_destroy callback restituisce false l'azione viene annullata e distrugge restituisce false. Vedi ActiveRecord :: Callbacks per ulteriori dettagli.


Ciao @ user740584 - grazie per la risposta. Cosa intendi con "esegue eventuali callback sul modello"?
BKSpurgeon,

3
@BKSpurgeon egli intende ActiveRecord :: richiamate: api.rubyonrails.org/classes/ActiveRecord/Callbacks.html . Uno di questi callback è model#before_destroyche può essere utilizzato per interrompere la destroy()chiamata finale in determinate condizioni.
Todd,

102

delete eliminerà solo i record dell'oggetto corrente da db ma non i record figlio associati da db.

destroy eliminerà il record dell'oggetto corrente da db e anche il record figlio associato da db.

Il loro uso conta davvero:

Se i tuoi oggetti padre multipli condividono oggetti figlio comuni, la chiamata destroya un oggetto padre specifico eliminerà gli oggetti figlio che sono condivisi tra altri genitori multipli.


5
Risposta brillante. grazie. aggiungerei che la terminologia che ho capito è che i bambini vengono "uccisi". brutale infanticidio.
BKSpurgeon,

Nella maggior parte dei casi in produzione si desidera utilizzare "
destro

No questo non è necessario.
Taimoor Changaiz,

Credo che la parola che si dovrebbe utilizzare per destroyè discendenti , non i bambini : secondo la documentazione, distruggono "crea un nuovo oggetto dagli attributi, e poi chiamate distruggono su di esso." rubydoc.info/docs/rails/4.1.7/ActiveRecord%2FRelation:destroy
Marco Lackovic

12

Quando invochi destroyo destroy_allsu un ActiveRecordoggetto, ActiveRecordviene avviato il processo di "distruzione", analizza la classe che stai eliminando, determina cosa dovrebbe fare per le dipendenze, passa attraverso le convalide, ecc.

Quando invochi deleteo delete_allsu un oggetto, ActiveRecordprova semplicemente a eseguire la DELETE FROM tablename WHERE conditionsquery sul db, senza eseguire altre ActiveRecordattività di livello.


4

Sì, c'è una grande differenza tra i due metodi Utilizzare delete_all se si desidera che i record vengano eliminati rapidamente senza richiamare i callback del modello

Se ti interessano i callback dei tuoi modelli, usa destroy_all

Dai documenti ufficiali

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

destroy_all (condizioni = zero) pubblico

Distrugge le condizioni corrispondenti ai record creando un'istanza di ogni record e chiamando il suo metodo di distruzione. I callback di ogni oggetto vengono eseguiti (inclusi: opzioni di associazione dipendenti e metodi before_destroy / after_destroy Observer). Restituisce la raccolta di oggetti che sono stati distrutti; ognuno verrà congelato, per riflettere che non è necessario apportare modifiche (poiché non possono essere mantenute).

Nota: l'istanza, l'esecuzione della richiamata e l'eliminazione di ciascun record possono richiedere molto tempo quando si rimuovono più record contemporaneamente. Genera almeno una query DELETE SQL per record (o forse più, per imporre i callback). Se si desidera eliminare rapidamente molte righe, senza preoccuparsi delle loro associazioni o callback, utilizzare invece delete_all.


2

Fondamentalmente "elimina" invia una query direttamente al database per eliminare il record. In quel caso Rails non sa quali sono gli attributi nel record che sta eliminando né se ci sono callback (come before_destroy).

Il metodo "destroy" prende l'id passato, recupera il modello dal database usando il metodo "find", quindi chiama distruggere su quello. Ciò significa che i callback sono attivati.

Si desidera utilizzare "elimina" se non si desidera attivare i callback o si desiderano prestazioni migliori. Altrimenti (e la maggior parte delle volte) vorrai usare "destro".


2

Molte risposte già; volevo continuare con un po 'di più.

documenti :

Per has_many, destroy e destroy_all chiamerà sempre il metodo di distruzione dei record da rimuovere in modo da eseguire i callback. Tuttavia, delete e delete_all eseguiranno la cancellazione in base alla strategia specificata dall'opzione: dipendente, oppure se viene fornita l'opzione no: dipendente, seguirà la strategia predefinita. La strategia predefinita è di non fare nulla (lasciare le chiavi esterne con gli ID parent impostati), tranne has_many: through, dove la strategia predefinita è delete_all (elimina i record di join, senza eseguire i loro callback).

Il deleteverbale funziona diversamente per ActiveRecord::Association.has_manye ActiveRecord::Base. Per quest'ultimo, delete eseguirà SQL DELETEe bypasserà tutte le validazioni / callback. Il primo verrà eseguito in base :dependentall'opzione passata all'associazione. Tuttavia, durante i test, ho riscontrato il seguente effetto collaterale in cui i callback venivano eseguiti solo deletee nondelete_all

dependent: :destroy Esempio:

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]]
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.