¿Cuál es la diferencia entre :destroy_all y :delete en Rails?

Una de las enseñanzas o instrucciones que se da cuando se diseñan bases de datos es que no debe haber información relacionada que no tenga su “dueño” o “padre”. Si un artículo tiene muchos comentarios y dicho artículo se elimina de la base de datos, tales comentarios también deben hacerlo.

En SQL a esto se le llama borrado en cascada. Para lograr esto en Rails usando ActiveRecord podemos usar la opción dependent y pasando algunas opciones disponibles.

A continuación trataré de explicar la diferencia entre las dos más comunes.

:destroy

Se utiliza así:

class User < ApplicationRecord
  has_many :payment_methods, dependent: :destroy
end

La opción :destroy le dice a ActiveRecord que elimine los registros hijos pero usando el método destroy de cada uno de ellos, es decir, primero los instancia y luego los elimina, uno por uno.

Si hay muchos registros hijos, será muy lento de esta forma.

Así luce mi consola al usar esta opción:

User Load (0.4ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT $1  [["LIMIT", 1]]
   (0.1ms)  BEGIN
PaymentMethod Load (0.3ms)  SELECT "payment_methods".* FROM "payment_methods" WHERE "payment_methods"."user_id" = $1  [["user_id", 1]]
  SQL (24.7ms)  DELETE FROM "payment_methods" WHERE "payment_methods"."id" = $1  [["id", 3]]
  SQL (0.3ms)  DELETE FROM "payment_methods" WHERE "payment_methods"."id" = $1  [["id", 2]]
  SQL (0.2ms)  DELETE FROM "payment_methods" WHERE "payment_methods"."id" = $1  [["id", 1]]
  SQL (0.4ms)  DELETE FROM "users" WHERE "users"."id" = $1  [["id", 1]]
    (0.3ms)  COMMIT

:delete_all

Se utiliza así:

class User < ApplicationRecord
  has_many :payment_methods, dependent: :delete_all
end

En cambio, la opción :delete_all lo que hace es una eliminación directa mediante una consulta SQL pura. Más eficiente si hay muchos registros asociados a un padre.

Así luce mi consola cuando uso esta opción:

User Load (0.4ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT $1  [["LIMIT", 1]]
   (0.1ms)  BEGIN
  SQL (0.3ms)  DELETE FROM "payment_methods" WHERE "payment_methods"."user_id" = $1  [["user_id", 3]]
  SQL (0.1ms)  DELETE FROM "users" WHERE "users"."id" = $1  [["id", 3]]
   (0.3ms)  COMMIT

Usar :delete_all no efectua el llamado a cualquier callback definido en el modelo.

Así que hay varios puntos aquí para diferenciar estas dos opciones:

  • :destroy: Instancia cada objeto. Llamado a callbacks. Menos eficiente.
  • :delete_all: Borrado directo por SQL. No llama a callbacks. Más eficiente.

Cualquiera de los dos es correcto usar, ya cada caso particular determina cual elegir al final.

Documentación.
Explicado en Stack Overflow.

Autor: cesc1989

Ingeniero de Sistemas que le gusta escribir y compartir sobre recursos que considera útiles, además que le gusta leer manga y ver anime.

Deja un comentario

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s