2010-07-09 7 views
2

Supposons que Song s ont beaucoup de Comment s; Comment puis-je:Tri par propriétés d'une association has_many

  1. Tracer une liste de tous les morceaux de la base de données triés par le nombre de commentaires qu'ils ont chacun? (C'est-à-dire, la chanson avec le plus de commentaires en premier, la chanson avec le moins de commentaires en dernier?)
  2. Même, mais trié par temps de création de commentaire? (C'est-à-dire, la chanson avec le commentaire le plus récemment créé en premier, la chanson avec le dernier commentaire créé en dernier?)

Répondre

1

Si vous avez besoin de trier par le nombre de commentaires qu'ils ont - alors que vous pouvez le faire directement en utilisant SQL - Je recommande fortement d'utiliser counter_cache - Voir: http://railscasts.com/episodes/23-counter-cache-column

Ofter que, juste définir l'ordre par l'option de find comme ceci:

Song.all(:order => "comments_count DESC");

Ceci est différent dans Rails 3 donc il dépend w chapeau que vous utilisez.

Je vous recommande également de mettre en cache le dernier commentaire créé sur le modèle Song pour vous faciliter la vie.

Vous devez faire cela avec un after_save rappel sur le modèle Comment avec quelque chose comme:

self.song.update_attributes!({:last_comment_added_at => Time.now.to_s(:db)})

+0

Je peux laisser le 'self' dans le rappel, non? –

+0

Oui, vous pouvez si vous voulez. ça va juste grimper la portée et frapper ce qu'il veut. J'ai tendance à ne pas partir parce que j'aime être explicite, mais c'est vraiment à vous de décider. –

6

1) Il y a deux façons de le faire, le plus simple serait contre le cache, vous le faites ma création d'une colonne pour maintenir le nombre et les rails permettra de garder le compte à la vitesse. la colonne dans ce cas serait comments_count

songs = Song.all(:order => "comments_count DESC") 

ou vous pouvez faire une requête très chic:

songs = Song.all(:joins => "LEFT JOIN comments ON songs.id = comments.song_id", 
       :select => "song.name, count(*)", 
       :group => "song.name", 
       :order => "count(*) DESC") 

quelques mises en garde avec la deuxième méthode, tout ce que vous voulez sélectionner dans les chansons que vous aurez besoin de inclure dans le groupe par déclaration. Si vous avez seulement besoin de tirer des chansons avec des commentaires, vous pouvez:

songs = Song.all(:joins => :comments, 
       :select => "song.name, count(*)", 
       :group => "song.name", 
       :order => "count(*) DESC") 

Ce qui semble plus agréable mais parce qu'il fait un intérieur vous joindre ne serait pas obtenir des chansons qui avaient aucun commentaire

2) juste un Include/joint

songs = Song.all(:include => :comments, :order => "comment.created_at" 

J'espère que cela aide!

+0

Grande explication. +1 –

+0

Merci; would 'Song.all (: jointures =>: commentaires,: order =>" comment.created_at "' fonctionnent également pour (2)? –

+0

jointures ne vous donnera que des chansons avec des commentaires, inclure vous donnera des chansons avec et sans commentaires. –

Questions connexes