Я создал систему личных сообщений, но у меня проблемы с почтой. Я хочу создать обычный почтовый ящик, где вы сможете видеть все свои разговоры. Я пытался что-то сделать, но я получаю результат всех сообщений, полученных пользователем, но я хочу отображать только последнее сообщение из каждого разговора.
SQL: у меня есть таблица сообщений с идентификатором, user_id (int), to_id (int), content (text), read (boolean).
Контроллер сообщений:
def inbox
@messages = Message.where("to_id = ? OR user_id = ? AND to_id != 0", current_user, current_user).order(created_at: :desc)
end
Вид:
<% @messages.each do |message| %>
<% to_user_id = User.find(message.to_id) %>
<% to_user_name = to_user_id.username %>
<b><p><%= to_user_name %></p></b>
<p>
<% if message.read == false %>
<b><%= link_to message.content, pm_path(to_user_id) %></b>
<% else %>
<%= link_to message.content, pm_path(to_user_id) %>
<% end %>
</p>
<% end %>
Надеюсь, я ясно и спасибо заранее.
Ответ 2 · max
Если вы правильно настроите ассоциации, это тривиально:
class User < ApplicationRecord
has_many :recieved_messages, class_name: 'Message', foreign_key: 'recipent_id'
has_many :sent_messages, class_name: 'Message', foreign_key: 'sender_id'
def all_messages
Message.where('recipient_id = :id OR sender_id = :id', id: id)
end
end
class Message < ApplicationRecord
belongs_to :recipient, class_name: 'User', inverse_of: :recieved_messages
belongs_to :sender, class_name: 'User', inverse_of: :sent_messages
def self.between(a,b)
.where('(recipient_id = :id OR sender_id = :id)', id: a)
.where('(recipient_id = :id OR sender_id = :id)', id: b)
end
end
# all messages recieved by the current user:
current_user.recieved_messages.order(created_at: :desc)
# all messages recieved by the current user:
current_user.sent_messages.order(created_at: :desc)
# all messages sent or recieved by the current user:
current_user.all_messages.order(created_at: :desc)
# all messages between two users
Message.between(current_user, some_other_user)
Ключом к получению любого сообщения между пользователями является:
WHERE (recipient_id = a OR sender_id = a) AND (recipient_id = b OR sender_id = b)
Но вместо этого вам следует подумать о создании модели разговора, чтобы присоединиться к ним.
При вызове .last будет получена самая старая запись, поскольку она находится в порядке убывания. Если вы хотите получить новейшее сообщение, используйте .first
Чтобы избежать проблемы с запросом N+1, убедитесь, что вы загружаете связанные записи:
@messages.eager_load(:recipient, :sender)
При итерации (в общем) используйте ассоциации вместо идентификаторов. Никогда не делайте что-то вроде User.find(message.to_id), так как это вызовет проблему с запросом N+1.
<% @messages.each do |message| %>
<p><b><%= message.recipent.name %></b></p>
<p>
<% if message.read? %>
<%= link_to message.content, pm_path(message.recipient) %>
<% else %>
<b><%= link_to message.content, pm_path(message.recipient) %></b>
<% end %>
</p>
<% end %>