Rails: dépendant =>: détruit VS: dépendant =>: delete_all

192

Dans les guides de rails, il est décrit comme ceci:

Les objets seront en outre détruits s'ils sont associés à :dependent => :destroy, et supprimés s'ils sont associés à:dependent => :delete_all

Bien, cool. Mais quelle est la différence entre être détruit et supprimé? J'ai essayé les deux et il semble faire la même chose.

Sergey
la source

Réponses:

200

La différence est avec le rappel.

Le :delete_allse fait directement dans votre application et supprime par SQL:

DELETE * FROM users where compagny_id = XXXX

Avec le :destroy, il y a une instanciation de tous vos enfants. Donc, si vous ne pouvez pas le détruire ou si chacun a le sien :dependent, ses rappels peuvent être appelés.

Shingara
la source
83
L'instanciation et l'appel de destroy sur chacun des objets enfants seront lents si vous avez beaucoup d'enfants (et n ^ 2 si vous avez des petits-enfants, et ainsi de suite). delete_all est le genre de solution "nuke it from orbit" où vous ne vous souciez pas / n'avez pas de callback avant / après destroy sur les modèles.
Ryan Bigg
131

Sur une association de modèle Rails, vous pouvez spécifier l' :dependentoption, qui peut prendre l'une des trois formes suivantes:

  • :destroy/:destroy_allLes objets associés sont détruits à côté de cet objet en appelant leur destroyméthode
  • :delete/:delete_allTous les objets associés sont détruits immédiatement sans appeler leur :destroyméthode
  • :nullifyToutes les clés étrangères des objets associés sont définies sur NULLsans appeler leurs saverappels
John Topley
la source
2
Voir api.rubyonrails.org/classes/ActiveRecord/Associations/… (recherchez "nullify") pour les rdocs faisant autorité.
mrm
21
Depuis Rails 3.0, il est également possible de spécifier :restrict. S'il est défini sur: restreindre, cet objet ne peut pas être supprimé s'il a un objet associé.
RocketR
17
il n'y a pas :deleteou des :destroy_alloptions par son apparence? L'option: dépendante attend soit: destroy,: delete_all,: nullify ou: restrict (: delete)
Mike Campbell
2
@MikeCampbell, :deleteet les :destroy_alloptions n'existent pas. Cependant, il existe des méthodes de classe sur les modèles qui sont appelées deleteet destroy_allcela pourrait donc être la raison de la confusion.
berezovskyi le
@MikeCampbell Il vous manque quelques options supplémentaires, Voir L'option: dépendante doit être l'une des [: destroy,: delete_all,: nullify,: restrict_with_error,: restrict_with_exception]
Pravin Mishra
30

See destroy supprime ses éléments associésdelete_all peut supprimer plusieurs données de la table self commeDELETE * FROM table where field = 'xyz'

: Options possibles dépendantes:

Contrôle ce qui arrive aux objets associés lorsque leur propriétaire est détruit. Notez que ceux-ci sont implémentés en tant que rappels, et Rails exécute les rappels dans l'ordre. Par conséquent, d'autres rappels similaires peuvent affecter le comportement: dépendant et le :dependentcomportement peut affecter d'autres rappels.

:destroy provoque la destruction de tous les objets associés.

:delete_all provoque la suppression directe de tous les objets associés de la base de données (les callbacks ne seront donc pas exécutés).

:nullifyprovoque la mise à NULL des clés étrangères. Les rappels ne sont pas exécutés.

:restrict_with_exception provoque la levée d'une exception s'il existe des enregistrements associés.

:restrict_with_error provoque l'ajout d'une erreur au propriétaire s'il existe des objets associés.

Si vous utilisez cette :throughoption, l'association sur le modèle de jointure doit être une appartenance à, et les enregistrements qui sont supprimés sont les enregistrements de jointure, plutôt que les enregistrements associés.

Manish Shrivastava
la source
3

En fait, la principale différence est que les rappels ne seront pas appelés lorsqu'ils ont :delete_allété utilisés. Mais lorsqu'elle est utilisée, :destroyla pile de rappels ( :after_destroy, :after_commit...) sera déclenchée.

Par conséquent, si vous avez des touch:déclarations dans les modèles en cours de suppression, il est préférable d'utiliser dependent: :delete_allplutôt «depend:: destroy».

atlascoder
la source