views:

244

answers:

2

Posts has_many Comments

I'm using searchlogic which will order by named scopes. So, I'd like a named scope that orders by each post's most recent comment.

named_scope :ascend_by_comment, :order => ...comments.created_at??...

I'm not sure how to do a :joins and get only the most recent comment and sort by its created_at field, all in a named_scope.

I'm using mysql, fyi.

EDIT:

This is the SQL query I'd be trying to emulate:

SELECT tickets.*, comments.created_at AS comment_created_at FROM tickets 
INNER JOIN 
(SELECT comments.ticket_id, MAX(comments.created_at) AS created_at 
  FROM comments group by ticket_id) comments 
ON tickets.id = comments.ticket_id ORDER BY comment_created_at DESC;
+1  A: 

Hi,

You can do that by joining or including the associated model through the scope, something like this will do the trick:

named_scope :ascend_by_comment, :joins => :comments, :order => "comments.created_at DESC"

jpemberthy
Multiple comments with an INNER JOIN will give duplicate posts, though. It's selecting ALL comments and the associated post.
wesgarrison
According to this ticket ( http://bit.ly/75FrSi ) named_scopes should not be returning a single object. It's scoping, not a finder, also they suggest to use, in this case, `ascend_by_comment.first` to return only 1 record instead of all, Hope you find it useful!
jpemberthy
I don't want my named scope to return one Post. I want it order the posts by their last comment. This named_scope would live in the Post model, not the Comment model (at least, that's how I think it should work.) So, I need to lookup one and only one comment per post, specifically the latest one.
wesgarrison
+1  A: 
named_scope :ascend_by_comment,
  :joins => "LEFT JOIN comments ON comments.post_id = posts.id",
  :group => "id",
  :select => "posts.*, max(comments.created_at) AS comment_created_max",
  :order => "comment_created_max ASC"

You can try to optimize it, but it should work and give you some hints how to do it.

Edit:

After you edited question and shown that you want inner join (no posts without comments?), you can of course change :joins => "..." with :joins => :comments.

MBO
I was going for the simplest case. I figured I could switch to a LEFT JOIN after I got one working with INNER JOIN. Also, this is for a helpdesk and every "post" has an initial "comment" so I'm okay with using INNER JOIN in this case.
wesgarrison
I added `:group => "posts.id"` for clarity in case I/anyone else wants to pull in the commment.id as well. Works perfectly with searchlogic and will_paginate.
wesgarrison