DEV Community

Francisco Quintero 🇨🇴
Francisco Quintero 🇨🇴

Posted on • Originally published at otroespacioblog.wordpress.com

¿Cuál es la diferencia entre :destroy 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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

:delete_all

Se utiliza así:

class User < ApplicationRecord
  has_many :payment_methods, dependent: :delete_all
end
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Usar :delete_all no efectúa 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.

Dicha eficiencia depende de lo que se necesite hacer y es un costo aceptable en muchas ocasiones.

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

Enlaces

Latest comments (0)