web-dev-qa-db-fra.com

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 utilisateur est réparti sur plusieurs tables. Je veux supprimer cet utilisateur et chaque enregistrement qui a son identifiant 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 processus. J'ai donc essayé delete_all. Il supprime uniquement l'utilisateur de sa propre table et le id de toutes les autres tables devient nul, mais laisse les enregistrements intacts dans celles-ci. Quelqu'un peut-il indiquer quel est le processus correct pour effectuer une tâche de ce type?

Je vois que destroy_all appelle la fonction destroy sur tous les objets associés, mais je veux simplement confirmer l'approche correcte.

179
glogic

Tu as raison. Si vous souhaitez supprimer l'utilisateur et tous les objets associés -> destroy_all Toutefois, si vous souhaitez uniquement supprimer l'utilisateur sans supprimer tous les objets associés -> delete_all

Selon ce post: Rails: dépendants =>: détruisent VS: dépendants =>: delete_all

  • destroy/destroy_all: Les objets associés sont détruits à côté de 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
222
Sandro Munda

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

Si vous devez faire quelque chose de radical, tel que destroy_all () sur un grand jeu de données, je ne le ferais probablement pas à partir de l'application et ne le manipulerais pas manuellement avec soin. Si le jeu de données est suffisamment petit, vous ne souffrirez pas autant.

21
Ryan Her

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

Donc au lieu de:

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

Tu peux faire :

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

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

16
simon-olivier

J'ai créé un petit bijo qui évite d'avoir à supprimer manuellement les enregistrements associés dans certaines circonstances.

Ce bijou 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 seront supprimés de manière récursive (c.-à-d. Entre modèles), sans en instancier aucun.

Notez que, tout comme dépendante:: delete ou dépendante:: delete_all, cette nouvelle option ne déclenche pas les rappels autour/avant/après_destroy des enregistrements dépendants.

Cependant, il est possible d'avoir des associations dépendantes:: détruisent n'importe où dans une chaîne de modèles autrement associés à dépendantes:: delete_recursively. L'option: destroy fonctionne normalement n'importe où sur la ligne, instanciant et détruisant tous les enregistrements pertinents et déclenchant ainsi leurs rappels.

1
Janosch