Polymorphic association in reverse
Let's say that I have two model开发者_StackOverflow中文版s - one called Post and one other called Video. I then have a third model - Comment - that is polymorphically associated to to each of these models.
I can then easily do post.comments and video.comments to find comments assosciated to records of these models. All easy so far.
But what if I want to go the other way and I want to find ALL posts and videos that have been commented on and display these in a list sorted on the date that the comment was made? Is this possible?
If it helps I'm working on Rails 3 beta.
probably not the best way, but this worked for me:
#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 }
hope this works for you too.
EDIT
i'm also assuming you're using has_many :comments, :as => :commentable
and belongs_to :commentable, :polymorphic => true
like KandadaBoggu suggested.
EDIT #2
actually, i think i made a mistake and the code above won't work... try this:
(Comment.find(:all, :order => "comment_date")).collect{ |x| x.commentable }
Try this:
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
Now you can run these commands:
Post.with_comments
Video.with_comments
Edit It looks like you want a single list with Videos and Posts. This is quite tricky, but doable. For every page you will have to execute 3 queries.
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
精彩评论