187 votes

delete_all vs destroy_all ?

Je cherche la meilleure approche pour supprimer des enregistrements d'une table. Par exemple, j'ai un utilisateur dont l'ID se trouve dans plusieurs tables. Je veux supprimer cet utilisateur et tous les enregistrements qui ont son ID dans toutes les tables.

u = User.find_by_name('JohnBoy')
u.usage_indexes.destroy_all
u.sources.destroy_all
u.user_stats.destroy_all
u.delete

Cela fonctionne et supprime toutes les références de l'utilisateur de toutes les tables, mais j'ai entendu dire que destroy_all était très lourd en termes de processus, alors j'ai essayé delete_all . Il ne fait que supprimer l'utilisateur de sa propre table d'utilisateurs et la id de toutes les autres tables sont rendues nulles, mais laissent les enregistrements intacts dans celles-ci. Quelqu'un peut-il me dire quelle est la procédure à suivre pour effectuer une tâche de ce type ?

Je vois que destroy_all appelle le destroy sur tous les objets associés mais je veux juste confirmer l'approche correcte.

236voto

Sandro Munda Points 12808

Vous avez raison. Si vous voulez supprimer l'Utilisateur et tous les objets associés -> destroy_all Cependant, si vous voulez juste supprimer l'utilisateur sans supprimer tous les objets associés -> delete_all

Selon ce post : Rails :dependent => :destroy VS :dependent => :delete_all

  • destroy / destroy_all : Les objets associés sont détruits en même temps que cet objet en appelant leur méthode destroy.
  • delete / delete_all : Tous les objets associés sont détruits immédiatement sans appeler leur méthode :destroy.

23voto

Ryan Her Points 325

Delete_all est une seule instruction SQL DELETE et rien de plus. destroy_all appelle destroy() sur tous les résultats correspondants de :conditions (si vous en avez une), ce qui pourrait être au moins NUM_OF_RESULTS instructions SQL.

Si vous devez faire quelque chose de drastique comme détruire_tout() sur un grand ensemble de données, je ne le ferais probablement pas depuis l'application et je le manipulerais manuellement avec précaution. Si le jeu de données est assez petit, vous ne souffrirez pas autant.

16voto

rijks Points 511

Pour éviter le fait que destroy_all instancie tous les enregistrements et les détruit un par un, vous pouvez l'utiliser directement à partir de la classe modèle.

Ainsi, au lieu de :

u = User.find_by_name('JohnBoy')
u.usage_indexes.destroy_all

Vous pouvez faire :

u = User.find_by_name('JohnBoy')
UsageIndex.destroy_all "user_id = #{u.id}"

Le résultat est une seule requête pour détruire tous les enregistrements associés.

1voto

Janosch Points 66

J'ai fait un petit bijou qui peut éviter de devoir supprimer manuellement les enregistrements associés dans certaines circonstances.

Cette gemme ajoute une nouvelle option pour les associations ActiveRecord :

dépendant : :delete_recursively

Lorsque vous détruisez un enregistrement, tous les enregistrements associés à l'aide de cette option sont supprimés de manière récursive (c'est-à-dire dans tous les modèles), sans qu'aucun d'entre eux ne soit instancié.

Notez que, tout comme dependent : :delete ou dependent : :delete_all, cette nouvelle option ne déclenche pas les callbacks around/before/after_destroy des enregistrements dépendants.

Cependant, il est possible d'avoir des associations dependent : :destroy n'importe où dans une chaîne de modèles qui sont autrement associés à dependent : :delete_recursively. L'option :destroy fonctionnera normalement n'importe où en amont ou en aval de la chaîne, en instanciant et en détruisant tous les enregistrements pertinents et en déclenchant ainsi également leurs rappels.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X