2010-03-17 7 views
1

Disons que j'ai deux modèles - un appelé Post et un autre appelé Vidéo. J'ai alors un troisième modèle - Commentaire - qui est polymorphiquement associé à chacun de ces modèles.Association polymorphe inversée

Je peux alors faire facilement post.comments et video.comments pour trouver des commentaires assosciated aux dossiers de ces modèles. Tout est facile jusqu'ici.

Mais si je veux aller dans l'autre sens et je veux trouver TOUS messages et vidéos qui ont été commentés et afficher ces derniers dans une liste triée à la date à laquelle le commentaire a été faite? Est-ce possible?

Si ça aide, je travaille sur Rails 3 beta.

Répondre

2

Essayez ceci:

class Post < ActiveRecord::Base 
    has_many :comments, :as => :commentable 
    named_scope :with_comments, :joins => :comments, 
           :order => "comments.created_at DESC" 
end 

class Video < ActiveRecord::Base 
    has_many :comments, :as => :commentable 
    named_scope :with_comments, :joins => :comments, 
           :order => "comments.created_at DESC" 
end 

class Comment < ActiveRecord::Base 
    belongs_to :commentable, :polymorphic => true 
end 

Maintenant, vous pouvez exécuter ces commandes:

Post.with_comments 
Video.with_comments 

Modifier On dirait que vous voulez une liste unique avec les vidéos et les messages. C'est assez difficile, mais faisable. Pour chaque page, vous devrez exécuter 3 requêtes.

def commented_videos_posts(page = 1, page_size = 30) 
    # query 1: get the lastest comments for posts and videos 
    comments = Comment.find_all_by_commentable_type(["Post", "Video"], 
       :select => "commentable_type, commentable_id, 
           MAX(created_at) AS created_at", 
       :group => "commentable_type, commentable_id" 
       :order => "created_at DESC", 
       :limit => page_size, :offset => (page-1)*page_size) 

    # get the video and post ids 
    post_ids, video_ids = [], [] 
    comments.each do |c| 
    post_ids << c.commentable_id if c.commentable_type == "Post" 
    video_ids << c.commentable_id if c.commentable_type == "Video" 
    end 

    posts, videos = {}, {} 

    # query 2: get posts 
    Post.all(post_ids).each{|p| posts[p.id] = p } 
    # query 3: get videos 
    Video.all(video_ids).each{|v| videos[v.id] = v } 

    # form one list of videos and posts 
    comments.collect do |c| 
    c.commentable_type == "Post" ? posts[c.commentable_id] : 
            videos[c.commentable_id] 
    end 
end 
+0

Merci pour votre réponse. Mais que faire si je veux combiner les deux? Je veux une liste des deux (combinés) qui est ordonnée par create_at? Une fusion si vous voulez ... – Erik

+0

Donc vous voulez une liste avec des vidéos et des posts classés par date de dernier commentaire? Voulez-vous obtenir les n derniers objets OU plus? Avez-vous besoin d'une pagination et d'un filtrage supplémentaire? –

+0

Exactement! Et oui, la pagination serait également ajoutée mais mon principal problème est de savoir comment combiner les deux listes ... des indices? – Erik

2

probablement pas la meilleure façon, mais cela a fonctionné pour moi:

#get all posts and videos 
posts_and_videos = Comment.all.collect{ |c| c.commentable } 

#order by last comment date 
posts_and_videos_ordered = posts_and_videos.sort{ |x,y| x.comment_date <=> y.comment_date } 

espère que cela fonctionne pour vous aussi.

EDIT

Je suis aussi en supposant que vous utilisez has_many :comments, :as => :commentable et belongs_to :commentable, :polymorphic => true comme suggéré KandadaBoggu.

EDIT # 2

En fait, je pense que je fait une erreur et le code ci-dessus ne fonctionne pas ... essayez ceci:

(Comment.find(:all, :order => "comment_date")).collect{ |x| x.commentable } 
+0

Merci! Je vais donner que j'essaye. Et oui, les associations sont correctement établies. :) – Erik