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?
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.
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.
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.
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.
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".
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]]