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.