delete_all vs destroy_all?

192

Estoy buscando el mejor enfoque para eliminar registros de una tabla. Por ejemplo, tengo un usuario cuyo ID de usuario se encuentra en muchas tablas. Quiero eliminar este usuario y cada registro que tenga su ID en todas las tablas.

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

Esto funciona y elimina todas las referencias del usuario de todas las tablas, pero escuché que el destroy_allproceso era muy pesado, así que lo intenté delete_all. Solo elimina al usuario de su propia tabla de usuario y el idde todas las otras tablas se anula, pero deja los registros intactos en ellas. ¿Alguien puede compartir cuál es el proceso correcto para realizar una tarea como esta?

Veo que destroy_allllama a la destroyfunción en todos los objetos asociados, pero solo quiero confirmar el enfoque correcto.

glogic
fuente

Respuestas:

243

Tienes razón. Si desea eliminar el Usuario y todos los objetos asociados -> destroy_all Sin embargo, si solo desea eliminar el Usuario sin suprimir todos los objetos asociados ->delete_all

De acuerdo con esta publicación: Rails: dependiente =>: destruir VS: dependiente =>: delete_all

  • destroy/ destroy_all: Los objetos asociados se destruyen junto con este objeto llamando a su método de destrucción
  • delete/ delete_all: Todos los objetos asociados se destruyen inmediatamente sin llamar a su método: destroy
Sandro Munda
fuente
80
También debe tenerse en cuenta que 1) las devoluciones de llamada no se llaman cuando se usa delete_all, y 2) destroy_allcrea instancias de todos los registros y los destruye uno a la vez, por lo que con un conjunto de datos muy grande, esto podría ser dolorosamente lento.
Dylan Markow
supongamos que estoy ejecutando un método before_destroy en el modelo: si uso delete_all, ¿este método no se ejecutará? en segundo lugar, si utilizo un método before_delete en mi modelo, ¿se ejecutará esto cuando ejecuto delete o delete_all en la consola de rails?
BKSpurgeon
23

delete_all es una sola declaración DELETE de SQL y nada más. destroy_all llama a destroy () en todos los resultados coincidentes de: condiciones (si tienes una) que podrían ser al menos NUM_OF_RESULTS sentencias SQL.

Si tiene que hacer algo drástico, como destroy_all () en un conjunto de datos grande, probablemente no lo haría desde la aplicación y lo manejaría manualmente con cuidado. Si el conjunto de datos es lo suficientemente pequeño, no le dolería tanto.

Ryan Her
fuente
16

Para evitar el hecho de que destroy_allcrea una instancia de todos los registros y los destruye uno a la vez, puede usarlo directamente desde la clase de modelo.

Entonces en lugar de:

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

Tu puedes hacer :

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

El resultado es una consulta para destruir todos los registros asociados.

Simon-Olivier
fuente
1
¿Llamará a las devoluciones de llamada de destrucción en los registros asociados, o es UsageIndex.destroy_allequivalente a UsageIntex.delete_all?
Magne
UsageIndex.destroy_allya no está disponible desde los rieles 3
fabriciofreitag
1

He creado una pequeña joya que puede aliviar la necesidad de eliminar manualmente los registros asociados en algunas circunstancias.

Esta gema agrega una nueva opción para las asociaciones ActiveRecord:

dependiente: delete_recursively

Cuando destruye un registro, todos los registros asociados con esta opción se eliminarán de forma recursiva (es decir, en todos los modelos), sin instanciar ninguno de ellos.

Tenga en cuenta que, al igual que dependiente:: eliminar o dependiente:: eliminar_todos, esta nueva opción no activa las devoluciones de llamada alrededor / antes / después de destruir los registros dependientes.

Sin embargo, es posible tener dependientes:: destruir asociaciones en cualquier lugar dentro de una cadena de modelos que de otro modo están asociadas con dependientes:: delete_recursively. La opción: destroy funcionará normalmente en cualquier parte de la línea, creando instancias y destruyendo todos los registros relevantes y, por lo tanto, también activando sus devoluciones de llamada.

Janosch
fuente
¡Esto es fantástico! Me pregunto por qué no más personas lo han visto / protagonizado / bifurcado en github ... ¿sigue funcionando bien?
Magne
@ Magia Gracias! Debería estar funcionando. Las pruebas se ejecutan en Ruby 2.4.1 y Rails 5.1.1. Hasta ahora solo lo he usado de forma privada y no en las principales aplicaciones de producción, de ahí la versión principal "0", pero nunca noté ningún problema. También es bastante simple, por lo que debería estar bien.
Janosch
Frio. :) Estoy ejecutando un proyecto en Ruby 2.3.1 y 'rails', '~> 4.1.14', y estoy tristemente obligado a confiar en activerecord (~> 4.1.0) debido a otras gemas. Veo que delete_recursively se resuelve en 0.9.0. ¿Existe una versión anterior que funcione con activerecord 4.1? No pude encontrar ninguno en la pestaña de lanzamientos en github.
Magne
1
@Magne Encontré que en realidad funciona para el registro activo desde 4.1.14 y he lanzado la versión 1.0.0 de gem con una dependencia relajada. Sin embargo, tenga en cuenta que la rama 4.1 de Rails ya no recibe actualizaciones de seguridad.
Janosch