Si no le importa ensuciarse las manos con un poco de SQL, puede usar un función de ventana para hacer el trabajo. Puede obtener los ID de publicación con 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
Si desea más columnas, agréguelas a ambas cláusulas SELECT. El #{user.id}
es, por supuesto, el destinatario que le interesa.
La parte interesante es la función de ventana:
rank() over (partition by thread_id order by created_at desc)
Esto dividirá la tabla en grupos según thread_id
(una especie de GRUPO POR localizado), ordénelos por la marca de tiempo (los más recientes primero) y luego rank()
da 1 para la primera entrada de cada grupo, 2 para la segunda, etc.
Dada una tabla que se ve así:
=> 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)
La consulta interna te da esto:
=> 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)
Y luego envolvemos la consulta externa para eliminar solo las coincidencias de clasificación 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)
Así que agregue las columnas adicionales que desee y envuélvalo todo en un Post.find_by_sql
y listo.