Se você não se importa em sujar as mãos com um pouco de SQL, você pode usar um função de janela para fazer o trabalho. Você pode obter os IDs de postagem com este 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
Se você quiser mais colunas, adicione-as a ambas as cláusulas SELECT. O
#{user.id}
é, obviamente, o destinatário em que você está interessado. A parte interessante é a função da janela:
rank() over (partition by thread_id order by created_at desc)
Isso irá particionar a tabela em grupos com base em
thread_id
(uma espécie de GROUP BY localizado), ordene-os pelo carimbo de data/hora (mais recente primeiro) e, em seguida, rank()
produz 1 para a primeira entrada em cada grupo, 2 para a segunda, etc. Dada uma tabela que se parece com isso:
=> 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)
A consulta interna fornece isso:
=> 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)
E, em seguida, envolvemos a consulta externa em torno disso para destacar apenas as correspondências do ranking superior:
=> 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)
Então, adicione as colunas extras que você deseja e envolva tudo em um
Post.find_by_sql
e pronto.