web-dev-qa-db-fra.com

Différence entre détruire et supprimer

Quelle est la différence entre 

@model.destroy et @model.delete 

Par exemple:

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

Est-ce vraiment important si j'utilise l'un ou l'autre?

170
user3383458

destroy exécute tous les rappels sur le modèle, alors que delete ne le fait pas.

Depuis l’API Rails :

  • ActiveRecord::Persistence.delete

    Supprime l'enregistrement dans la base de données et gèle cette instance pour indiquer qu'aucune modification ne doit être apportée (car elles ne peuvent pas être persistées). Renvoie l'instance figée.

    La ligne est simplement supprimée avec une instruction SQL DELETE sur la clé primaire de l'enregistrement et aucun rappel n'est exécuté.

    Pour appliquer les rappels before_destroy et after_destroy de l'objet ou toute option d'association dépendante, utilisez #destroy.

  • ActiveRecord::Persistence.destroy

    Supprime l'enregistrement dans la base de données et gèle cette instance pour indiquer qu'aucune modification ne doit être apportée (car elles ne peuvent pas être persistées).

    Il y a une série de rappels associés à détruire. Si le rappel before_destroy renvoie false, l'action est annulée et destroy renvoie false. Voir ActiveRecord :: Callbacks pour plus de détails.

243
user740584

delete supprimera uniquement l'enregistrement d'objet actuel de la base de données, mais pas les enregistrements enfants associés de la base de données.

destroy supprimera l'enregistrement d'objet actuel de la base de données, ainsi que l'enregistrement de ses enfants associés de la base de données.

Leur utilisation compte vraiment:

Si plusieurs objets parents partagent des objets enfants communs, l'appel de destroy à un objet parent spécifique supprimera les objets enfants partagés entre plusieurs autres parents.

81
Taimoor Changaiz

Lorsque vous appelez destroy ou destroy_all sur un objet ActiveRecord, le processus ActiveRecord 'destruction' est lancé, il analyse la classe que vous supprimez, il détermine ce qu'il doit faire pour les dépendances, effectue des validations, etc.

Lorsque vous appelez delete ou delete_all sur un objet, ActiveRecord tente simplement d'exécuter la requête DELETE FROM tablename WHERE conditions sur la base de données, sans effectuer aucune autre tâche ActiveRecord-level.

11
nickcen

Oui, il existe une différence majeure entre les deux méthodes Utilisez delete_all si vous souhaitez que les enregistrements soient supprimés rapidement sans que les rappels de modèle ne soient appelés.

Si vous vous souciez des callbacks de vos modèles, utilisez destroy_all

De la documentation officielle

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

destroy_all (conditions = nil) public

Détruit les conditions de correspondance des enregistrements en instanciant chaque enregistrement et en appelant sa méthode destroy. Les rappels de chaque objet sont exécutés (y compris: options d'association dépendante et méthodes Observer before_destroy/after_destroy). Retourne la collection d'objets qui ont été détruits; chacun sera gelé, pour refléter cela aucun changement ne doit être effectué (car ils ne peuvent pas être persistés).

Remarque: Instanciation, exécution de rappel et suppression de chaque enregistrement peut prendre beaucoup de temps lorsque vous supprimez plusieurs enregistrements à la fois. Il génère au moins une requête SQL DELETE par enregistrement (ou éventuellement plus, pour appliquer vos rappels). Si vous souhaitez supprimer plusieurs lignes rapidement, sans se soucier de leurs associations ou rappels, utilisez delete_all au lieu.

4
jamesc

En gros, "supprimer" envoie une requête directement à la base de données pour supprimer l'enregistrement. Dans ce cas, Rails ne sait pas quels attributs se trouvent dans l'enregistrement qu'il est en train de supprimer ni s'il y a des rappels (tels que before_destroy).

La méthode "destroy" prend l'identifiant passé, récupère le modèle de la base de données à l'aide de la méthode "find", puis appelle destroy sur celui-ci. Cela signifie que les rappels sont déclenchés.

Vous voudriez utiliser "delete" si vous ne voulez pas que les rappels soient déclenchés ou si vous voulez de meilleures performances. Sinon (et la plupart du temps), vous voudrez utiliser "détruire".

2
Severin

Beaucoup de réponses déjà; voulait sauter avec un peu plus.

docs :

Pour has_many, destroy et destroy_all appellent toujours la méthode destroy du ou des enregistrements à supprimer afin que les rappels soient exécutés. Cependant, delete et delete_all procéderont soit à la suppression selon la stratégie spécifiée par l'option: dépendante, soit si l'option non: dépendante est donnée, elle suivra la stratégie par défaut. La stratégie par défaut consiste à ne rien faire (laissez les clés étrangères avec les identifiants parent définis), à l'exception de has_many: through, où la stratégie par défaut est delete_all (supprimez les enregistrements de jointure, sans exécuter leurs rappels).

Le verbage delete fonctionne différemment pour ActiveRecord::Association.has_many et ActiveRecord::Base. Pour ce dernier, delete exécutera SQL DELETE et contournera toutes les validations/rappels. Le premier sera exécuté en fonction de l’option :dependent transmise à l’association. Cependant, au cours des tests, j’ai constaté l’effet secondaire suivant: les rappels n’étaient exécutés que pour delete et non delete_all.

dependent: :destroy Exemple: 

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]]
0
David Zhang