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 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.
Top comments (0)