2009-01-23 4 views
1

J'ai donc quelques modèles configurés qui peuvent chacun avoir un commentaire. Je l'ai mis en place en utilisant has_many_polymorphs, mais je commence à rencontrer des problèmes qui ne fonctionnent pas comme je le pense.Rails has_many_polymorphs à l'envers?

Par exemple:

class Project < ActiveRecord::Base 
end 

class Message < ActiveRecord::Base 
    has_many_polymorphs :consumers, 
    :from => [:projects, :messages], 
    :through => :message_consumers, 
    :as => :comment # Self-referential associations have to rename the non-polymorphic key 
end 

class MessageConsumer < ActiveRecord::Base 
    # Self-referential associations have to rename the non-polymorphic key 
    belongs_to :comment, :foreign_key => 'comment_id', :class_name => 'Message' 

    belongs_to :consumer, :polymorphic => true 
end 

Dans ce cas, le message pas supprimés lorsque le projet est supprimé, parce que le message est vraiment le parent dans la relation. Je l'ai simplifié un peu pour l'exemple, mais il y a d'autres modèles qui ont un message, et il y a aussi des pièces jointes qui fonctionnent de façon similaire.

Quelle serait la bonne façon de configurer ceci afin que les enfants soient supprimés lorsque le parent est supprimé? J'espère ne pas avoir un million de tables, mais je n'arrive pas à trouver un autre moyen de le faire.

Répondre

1

Quand vous dites "pour que les enfants soient enlevés quand le parent est supprimé?", Pouvez-vous donner un exemple? C'est à dire. Quand un projet est supprimé, je souhaite que tous ses messages soient également supprimés? Que se passe-t-il lorsque vous supprimez un message, voulez-vous supprimer également tout autre élément (par exemple, toutes les entrées de message_consumer correspondantes)?


MISE À JOUR

OK, has_many_polymorphs supprimera automatiquement "orphelins" message_consumer s. Votre problème étant qu'un message peut avoir plusieurs utilisateurs, la suppression d'un projet peut ne pas suffire à supprimer tous les messages associés (car les autres consommateurs peuvent en dépendre.)

Dans ce cas particulier, vous pouvez définir jusqu'à un rappel after_destroy à MessageConsumer, pour vérifier s'il existe encore d'autres MessageConsumer applications (autres que moi) qui font référence à la Message et, en leur absence, supprimer aussi le message, par exemple:

class MessageConsumer < ActiveRecord::Base 

    ... 

    after_destroy :delete_orphaned_messages 

    def delete_orphaned_messages 
    if MessageConsumer.find(:first, :conditions => [ 'comment_id = ?', self.comment_id]).empty? 
     self.comment.delete 
    end 
    end 
end 

Tout cela se passe à l'intérieur une transaction, donc toutes les suppressions réussissent ou aucune ne réussit.

que vous devez être conscient des conditions de course possibles où une session arriverait à la conclusion qu'une Message ne sert plus, alors qu'un autre peut être en train de créer une nouvelle MessageConsumer pour cette même Message exacte. Cela peut être appliqué par l'intégrité référentielle au niveau de la base de données (ajouter des contraintes de clés étrangères, ce qui rendra l'une des deux sessions échouée, et gardera votre base de données dans un état cohérent), ou de verrouillage (pouah!)

+0

Oui, lorsqu'un projet est supprimé, le message doit également être supprimé. Toutes les entrées de message_consumer orphelines doivent également être nettoyées. – Karl

0

simplifier beaucoup cela en utilisant acts_as_commentable.

+0

Le message est juste un exemple, il y a quelques autres classes dans le projet qui font la même chose. Je ne suis pas sûr que cela corresponde vraiment à ce que agit_as_commentable résout. – Karl