Необходимо рассмотреть два набора сообщений:
- Те, где
from_id
- текущий пользователь.
- Те, где
to_id
- текущий пользователь.
Я бы пошел с find_by_sql
и позволил бы базе данных сделать всю работу:
chatting_with = User.find_by_sql(%Q{
select * from users where id in (
select to_id as user_id from messages where from_id = :the_user
union all
select from_id as user_id from messages where to_id = :the_user
)
}, :the_user => the_user_in_question.id)
SQL UNION просто выполняет последовательное объединение двух результирующих наборов, поэтому приведенный выше захватит всех пользователей, которым the_user_in_question
отправил сообщения, и объединит их с пользователями, отправившими сообщения на the_user_in_question
; В результате будут все пользователи, которые участвуют в беседах с the_user_in_question
в виде массива пользовательских экземпляров. Поскольку в UNION есть IN
, вы можете использовать UNION ALL, чтобы избежать дополнительной работы в UNION.
Возможно, вы захотите обернуть это в метод класса в сообщении:
def self.conversations_involving(user)
User.find_by_sql(%Q{
select * from users where id in (
select to_id as user_id from messages where from_id = :the_user
union all
select from_id as user_id from messages where to_id = :the_user
)
}, :the_user => user.id)
end
И тогда вы могли бы просто сказать что-то вроде:
@other_users = Message.conversations_involving(current_user)
в вашем контроллере.
Вы также хотите добавить индексы к messages.from_id
и messages.to_id
в вашей базе данных.