Ако нямате нищо против да си изцапате ръцете с малко SQL, можете да използвате прозоречна функция за да се свърши работата. Можете да получите идентификаторите на публикацията с този 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
Ако искате повече колони, добавете ги към двете клаузи SELECT. #{user.id}
е, разбира се, получателят, от когото се интересувате.
Интересната част е функцията прозорец:
rank() over (partition by thread_id order by created_at desc)
Това ще раздели таблицата на групи въз основа на thread_id
(нещо като локализирано ГРУПИРАНЕ ПО), подредете ги по клеймото за време (първо най-новите) и след това rank()
дава 1 за първия запис във всяка група, 2 за втория и т.н.
Дадена е таблица, която изглежда така:
=> 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)
Вътрешната заявка ви дава следното:
=> 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)
И след това обгръщаме външната заявка около това, за да отделим само най-високо класираните съвпадения:
=> 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)
Така че добавете допълнителните колони, които искате, и увийте всичко в Post.find_by_sql
и сте готови.