delete_all vs destroy_all?


193

Sto cercando l'approccio migliore per eliminare i record da una tabella. Ad esempio, ho un utente il cui ID utente si trova su molte tabelle. Voglio eliminare questo utente e ogni record che ha il suo ID in tutte le tabelle.

u = User.find_by_name('JohnBoy')
u.usage_indexes.destroy_all
u.sources.destroy_all
u.user_stats.destroy_all
u.delete

Funziona e rimuove tutti i riferimenti dell'utente da tutte le tabelle, ma ho sentito che destroy_allera molto pesante, quindi ho provato delete_all. Rimuove l'utente dalla propria tabella utente e idtutte le altre tabelle vengono rese nulle, ma i record rimangono intatti in esse. Qualcuno può condividere qual è il processo corretto per eseguire un'attività come questa?

Vedo che destroy_allchiama la destroyfunzione su tutti gli oggetti associati ma voglio solo confermare l'approccio corretto.

Risposte:


244

Hai ragione. Se si desidera eliminare l'utente e tutti gli oggetti associati -> destroy_all Tuttavia, se si desidera eliminare l'utente senza eliminare tutti gli oggetti associati ->delete_all

Secondo questo post: Rotaie: dipendente =>: distruggere VS: dipendente =>: delete_all

  • destroy/ destroy_all: Gli oggetti associati vengono distrutti accanto a questo oggetto chiamando il loro metodo di distruzione
  • delete/ delete_all: Tutti gli oggetti associati vengono immediatamente distrutti senza chiamare il loro metodo: destroy

80
Va inoltre notato che 1) I callback non vengono chiamati durante l'utilizzo delete_all e 2) destroy_allcrea un'istanza di tutti i record e li distrugge uno alla volta, quindi con un set di dati molto grande, questo potrebbe essere dolorosamente lento.
Dylan Markow,

supponiamo che sto eseguendo un metodo before_destroy nel modello - se uso delete_all, questo metodo non funzionerà? in secondo luogo, se utilizzo un metodo before_delete nel mio modello, verrà eseguito quando eseguo delete o delete_all nella console di rails?
BKSpurgeon,

23

delete_all è una singola istruzione DELETE SQL e nient'altro. destroy_all chiama destroy () su tutti i risultati corrispondenti di: condizioni (se ne hai uno) che potrebbero essere almeno NUM_OF_RESULTS istruzioni SQL.

Se dovessi fare qualcosa di drastico come destroy_all () su un set di dati di grandi dimensioni, probabilmente non lo farei dall'app e gestirlo manualmente con cura. Se il set di dati è abbastanza piccolo, non ti farebbe molto male.


16

Per evitare il fatto destroy_all crea un'istanza di tutti i record e li distrugge uno alla volta, è possibile utilizzarlo direttamente dalla classe del modello.

Quindi invece di:

u = User.find_by_name('JohnBoy')
u.usage_indexes.destroy_all

Tu puoi fare :

u = User.find_by_name('JohnBoy')
UsageIndex.destroy_all "user_id = #{u.id}"

Il risultato è una query per distruggere tutti i record associati


1
Chiamerà i callback di distruzione sui record associati o è UsageIndex.destroy_allequivalente a UsageIntex.delete_all?
Magne,

UsageIndex.destroy_allnon è più disponibile da rotaie 3
fabriciofreitag il

1

Ho creato una piccola gemma che può alleviare la necessità di eliminare manualmente i record associati in alcune circostanze.

Questa gemma aggiunge una nuova opzione per le associazioni ActiveRecord:

dipendente:: delete_recursively

Quando si distrugge un record, tutti i record associati utilizzando questa opzione verranno eliminati in modo ricorsivo (ad esempio tra i modelli), senza istanziarne uno.

Si noti che, proprio come dipendente:: elimina o dipendente:: delete_all, questa nuova opzione non attiva i callback around / before / after_destroy dei record dipendenti.

Tuttavia, è possibile avere dipendenti:: distruggere le associazioni ovunque all'interno di una catena di modelli che sono altrimenti associati a dipendenti:: delete_recursively. L'opzione: destroy funzionerà normalmente ovunque su o giù per la linea, creando un'istanza e distruggendo tutti i record rilevanti e attivando così anche i loro callback.


È fantastico! Mi chiedo perché non più persone abbiano guardato / recitato / biforcuto su Github .. funziona ancora bene?
Magne,

@Magne Grazie! Dovrebbe funzionare. I test vengono eseguiti su Ruby 2.4.1 e Rails 5.1.1. Finora l'ho usato solo privatamente e non nelle principali app di produzione, quindi nella versione principale "0", ma non ho mai notato alcun problema. È anche abbastanza semplice, quindi dovrebbe andare bene.
Janosch,

Freddo. :) Sto eseguendo un progetto su Ruby 2.3.1, e 'rails', '~> 4.1.14', e sono tristemente costretto a fare affidamento su activerecord (~> 4.1.0) a causa di altre gemme. Vedo che delete_recursively è stato risolto in 0.9.0. Esiste una versione precedente che funzionerebbe con activerecord 4.1? Non ne ho trovato nessuno nella scheda dei rilasci su github.
Magne,

1
@Magne Ho trovato che funziona effettivamente per activerecord a partire da 4.1.14 e ho rilasciato gem versione 1.0.0 con una dipendenza rilassata. Tuttavia, tieni presente che il ramo 4.1 di Rails non riceve più aggiornamenti di sicurezza.
Janosch,
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.