2010-06-02 5 views
1

J'ai un contrôleur de poste qui a beaucoup de commentaires. Le modèle de message a un champ appelé has_comments qui est un booléen (donc je peux rapidement sélectionner dans la base de données uniquement les messages qui ont des commentaires). Pour créer un nouveau commentaire pour une publication, j'utilise l'action create de mon contrôleur de commentaires. Après avoir créé le commentaire, je dois mettre à jour le champ has_comments de mon message et le définir sur true.Où mettre un morceau de code dans Ruby on Rails?

Je peux mettre à jour ce champ de l'action create de mon contrôleur de commentaires, mais cela ne semble pas correct - je pense que je devrais vraiment utiliser l'action update du poste, mais je ne suis pas sûr que c'est bon d'appeler il (via send?) à partir de l'action create du contrôleur de commentaires.

Où le code de mise à jour du poste devrait-il être? Merci!

Répondre

2

Pourquoi encombrer votre base de données avec une autre colonne lorsque l'interface est programmatique? Faire has_comments une méthode sur le Post:

def has_comments 
    comments.size > 0 
end 

mettre en œuvre ensuite un counter_cache comme suggéré de réduire la charge de la requête.

EDIT: Vous pouvez également, après la mise en œuvre d'un cache de compteur, vous pouvez utiliser un named_scope sur le Post pour récupérer tous les messages qui ont des commentaires, à l'aide d'une seule requête, si c'est le principal objectif:

class Comment 
    belongs_to :post, :counter_cache => true 
end 

class Post 
    named_scope :with_comments, {:conditions=>"comments_count > 0"} 
end 

EDIT: Vous peut également éviter le fameux problème de requête n + 1 par une utilisation judicieuse de: include:

posts = Post.find(:all, :include => :comments) 
+0

Cela permettra également d'éviter les incohérences (par exemple dans le cas d'un commentaire supprimé), que vous auriez à considérer autrement – averell

+0

D'accord. Utiliser une nouvelle colonne + callbacks est lourd et cassant pour ce qui devrait être une méthode simple. –

+0

alors comment allez-vous sur la sélection de tous les messages qui ont un commentaire de la base de données sans aller chercher tous les messages, puis en comptant les commentaires pour chacun d'eux, puis en filtrant le résultat? C'est beaucoup plus de mémoire que de simplement changer une valeur dans une colonne. n'est-ce pas? –

1

Vous pouvez utiliser le rappel before_save dans votre modèle.

Encore mieux serait d'utiliser built in: option counter_cache qui met automatiquement en cache le nombre de commentaires pour chaque publication. (Voir http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#M001835 sous options pour belongs_to)

+0

merci. quel modèle dois-je mettre le callback before_save? Je ne pense pas que le parent (c'est-à-dire le post-modèle) soit enregistré lorsqu'un commentaire est créé/mis à jour. Mais mettre du code qui a mis à jour le post (parent) dans le modèle de commentaire n'est pas très approprié, n'est-ce pas? Qu'est-ce que j'ai pour la méthode de mise à jour de post controller, alors? –

+0

Vous devriez le mettre dans les commentaires before_save. Il est possible de mettre à jour la publication lorsqu'un nouveau commentaire est créé. Fondamentalement, les Rails font la même chose quand vous définissez: counter_cache pour belongs_to (qui est dans le modèle Comment). –

+1

En fait, 'before_save' n'est pas le rappel correct. J'utiliserais after_save à la place, et sur le modèle 'Comment', comme mentionné ci-dessous. Parce que si quelque chose se passait mal au moment de la sauvegarde, vous avez incorrectement mis à jour le champ 'has_comments'. Mais, en utilisant le ': counter_cache' est une très bonne solution et va gérer tout le travail lourd pour vous. – nathanvda

1

utilisation after_save dans le modèle de commentaire

def after_save 
    #this will set "has_comment" of the Specified Post to true if it's not true already 
    self.post.update_attribute('has_comment', true) unless self.post.has_comment 
end 
+0

Merci. Est-il approprié de mettre à jour le parent d'un modèle (le commentaire du commentaire) à travers le modèle de l'enfant (modèle de commentaire)? Pourquoi ne pas envoyer la méthode 'update' du contrôleur de posts ici? –

+0

Aucune méthode de mise à jour ne mettra à jour toutes les données avec des données déjà enregistrées dans la base de données et définira has_comment = true.update_attributes de la méthode de mise à jour appelle aussi tous les callbacks dans Postmodel alors que update_attribute ne l'est pas, donc augmentez votre temps d'exécution. – Salil