Om du inte har något emot att smutsa ner händerna med lite SQL kan du använda en fönsterfunktion för att få jobbet gjort. Du kan få post-ID:n med denna SQL:
select id
from (
select id,
rank() over (partition by thread_id order by created_at desc)
from posts
where receiver_id = #{user.id}
) as dt
where rank = 1
Om du vill ha fler kolumner lägg till dem i båda SELECT-satserna. #{user.id}
är naturligtvis den mottagare du är intresserad av.
Det intressanta är fönsterfunktionen:
rank() over (partition by thread_id order by created_at desc)
Detta kommer att dela upp tabellen i grupper baserade på thread_id
(typ av en lokaliserad GROUP BY), ordna dem efter tidsstämpeln (senaste först) och sedan rank()
ger 1 för den första posten i varje grupp, 2 för den andra osv.
Med tanke på en tabell som ser ut så här:
=> select * from posts;
id | receiver_id | thread_id | created_at
----+-------------+-----------+---------------------
1 | 1 | 2 | 2011-01-01 00:00:00
2 | 1 | 2 | 2011-02-01 00:00:00
3 | 1 | 2 | 2011-03-01 00:00:00
4 | 1 | 3 | 2011-01-01 00:00:00
5 | 1 | 4 | 2011-01-01 00:00:00
6 | 1 | 3 | 2011-01-01 13:00:00
7 | 2 | 11 | 2011-06-06 11:23:42
(7 rows)
Den inre frågan ger dig detta:
=> select id, rank() over (partition by thread_id order by created_at desc)
from posts
where receiver_id = 1;
id | rank
----+------
3 | 1
2 | 2
1 | 3
6 | 1
4 | 2
5 | 1
(6 rows)
Och sedan lindar vi den yttre frågan runt det för att bara ta bort topprankade matcher:
=> select id
from (
select id,
rank() over (partition by thread_id order by created_at desc)
from posts
where receiver_id = 1
) as dt
where rank = 1;
id
----
3
6
5
(3 rows)
Så lägg till de extra kolumner du vill ha och slå ihop det hela i en Post.find_by_sql
och du är klar.