Diferencia entre destruir y eliminar


210

Cuál es la diferencia entre

@model.destroy y @model.delete

Por ejemplo:

Model.find_by(col: "foo").destroy_all
//and
Model.find_by(col: "foo").delete_all

¿Realmente importa si uso el uno o el otro?

Respuestas:


289

Básicamente destroyejecuta cualquier devolución de llamada en el modelo mientras deleteno lo hace.

De la API de Rails :

  • ActiveRecord::Persistence.delete

    Elimina el registro en la base de datos y congela esta instancia para reflejar que no se deben realizar cambios (ya que no se pueden persistir). Devuelve la instancia congelada.

    La fila simplemente se elimina con una instrucción DELETE de SQL en la clave primaria del registro, y no se ejecutan devoluciones de llamada.

    Para aplicar las devoluciones de llamada antes_destruir y después_destruir del objeto o cualquiera: opciones de asociación dependientes, use #destroy.

  • ActiveRecord::Persistence.destroy

    Elimina el registro en la base de datos y congela esta instancia para reflejar que no se deben realizar cambios (ya que no se pueden persistir).

    Hay una serie de devoluciones de llamada asociadas con destruir. Si la devolución de llamada before_destroy devuelve falso, la acción se cancela y destruir devuelve falso. Vea ActiveRecord :: Callbacks para más detalles.


Hola @ user740584: gracias por tu respuesta. ¿Qué quieres decir con "ejecuta alguna devolución de llamada en el modelo"?
BKSpurgeon

3
@BKSpurgeon se refiere a ActiveRecord :: Callbacks: api.rubyonrails.org/classes/ActiveRecord/Callbacks.html . Una de estas devoluciones de llamada es la model#before_destroyque se puede usar para detener la destroy()llamada final bajo ciertas condiciones.
Todd

102

delete solo eliminará el registro de objeto actual de db pero no sus registros secundarios asociados de db.

destroy eliminará el registro de objeto actual de db y también su registro secundario asociado de db.

Su uso realmente importa:

Si sus múltiples objetos primarios comparten objetos secundarios comunes, al invocar destroyun objeto primario específico se eliminarán los objetos secundarios que se comparten entre otros múltiples padres.


55
Brillante respuesta. gracias. Añadiría que la terminología, según tengo entendido, es que los niños son "asesinados". infanticidio brutal
BKSpurgeon

En la mayoría de los casos en producción, desea usar 'destruir'
Outside_Box

No, esto no es necesario.
Taimoor Changaiz

Creo que la palabra que deberías usar para destroyes descendientes , no hijos : de acuerdo con la documentación, destruir "crea un nuevo objeto a partir de los atributos, y luego llama a destruir en él". rubydoc.info/docs/rails/4.1.7/ActiveRecord%2FRelation:destroy
Marco Lackovic

12

Cuando invoca destroyo destroy_allsobre un ActiveRecordobjeto, elActiveRecord se inicia el proceso de 'destrucción', analiza la clase que está eliminando, determina qué debe hacer para las dependencias, ejecuta validaciones, etc.

Cuando invoca deleteo delete_allsobre un objeto, ActiveRecordsimplemente intenta ejecutar la DELETE FROM tablename WHERE conditionsconsulta en el DB, sin realizar otras ActiveRecordtareas de nivel.


4

Sí, existe una gran diferencia entre los dos métodos. Use delete_all si desea que los registros se eliminen rápidamente sin que se llame a las devoluciones de llamada del modelo

Si te interesan las devoluciones de llamada de tus modelos, usa destroy_all

De los documentos oficiales

http://apidock.com/rails/ActiveRecord/Base/destroy_all/class

destroy_all (condiciones = nulo) public

Destruye las condiciones de coincidencia de registros creando instancias de cada registro y llamando a su método de destrucción. Las devoluciones de llamada de cada objeto se ejecutan (incluidas: opciones de asociación dependiente y métodos de observador before_destroy / after_destroy). Devuelve la colección de objetos que fueron destruidos; cada uno se congelará para reflejar que no se deben realizar cambios (ya que no se pueden persistir).

Nota: La creación de instancias, la ejecución de devolución de llamada y la eliminación de cada registro pueden llevar mucho tiempo cuando se eliminan muchos registros a la vez. Genera al menos una consulta DELETE de SQL por registro (o posiblemente más, para aplicar sus devoluciones de llamada). Si desea eliminar muchas filas rápidamente, sin preocuparse por sus asociaciones o devoluciones de llamada, use delete_all en su lugar.


2

Básicamente, "eliminar" envía una consulta directamente a la base de datos para eliminar el registro. En ese caso, Rails no sabe qué atributos hay en el registro que está eliminando ni si hay devoluciones de llamada (como before_destroy).

El método "destroy" toma la identificación pasada, recupera el modelo de la base de datos usando el método "find" y luego llama a destroy en ese caso. Esto significa que se activan las devoluciones de llamada.

Desea usar "eliminar" si no desea que se activen las devoluciones de llamada o si desea un mejor rendimiento. De lo contrario (y la mayoría de las veces) querrá usar "destruir".


2

Muchas respuestas ya; quería saltar con un poco más.

docs :

Para has_many, destroy y destroy_all siempre llamará al método de destrucción de los registros que se eliminan para que se ejecuten las devoluciones de llamada. Sin embargo, delete y delete_all harán la eliminación de acuerdo con la estrategia especificada por la opción: dependiente, o si no se da la opción: dependiente, entonces seguirá la estrategia predeterminada. La estrategia predeterminada es no hacer nada (dejar las claves foráneas con los ID de los padres establecidos), excepto has_many: through, donde la estrategia predeterminada es delete_all (eliminar los registros de unión, sin ejecutar sus devoluciones de llamada).

El deleteverbage funciona de manera diferente para ActiveRecord::Association.has_manyy ActiveRecord::Base. Para este último, eliminar ejecutará SQL DELETEy omitirá todas las validaciones / devoluciones de llamada. El primero se ejecutará en función de la :dependentopción pasada a la asociación. Sin embargo, durante las pruebas, encontré el siguiente efecto secundario donde las devoluciones de llamada solo se ejecutaron deletey nodelete_all

dependent: :destroy Ejemplo:

class Parent < ApplicationRecord
   has_many :children,
     before_remove: -> (_) { puts "before_remove callback" },
     dependent: :destroy
end

class Child < ApplicationRecord
   belongs_to :parent

   before_destroy -> { puts "before_destroy callback" }
end

> child.delete                            # Ran without callbacks
Child Destroy (99.6ms)  DELETE FROM "children" WHERE "children"."id" = $1  [["id", 21]]

> parent.children.delete(other_child)     # Ran with callbacks
before_remove callback
before_destroy callback
Child Destroy (0.4ms)  DELETE FROM "children" WHERE "children"."id" = $1  [["id", 22]]

> parent.children.delete_all              # Ran without callbacks
Child Destroy (1.0ms)  DELETE FROM "children" WHERE "children"."parent_id" = $1  [["parent_id", 1]]
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.