Rails Отображать только последнее личное сообщение от пользователя в папке «Входящие»

Я создал систему личных сообщений, но у меня проблемы с почтой. Я хочу создать обычный почтовый ящик, где вы сможете видеть все свои разговоры. Я пытался что-то сделать, но я получаю результат всех сообщений, полученных пользователем, но я хочу отображать только последнее сообщение из каждого разговора.

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 %>

Надеюсь, я ясно и спасибо заранее.


person Omer TaB    schedule 14.10.2017    source источник


Ответы (2)


Попробуй это

@messages = Message.find_by("(to_id = ? OR user_id = ?) AND to_id != 0", current_user, current_user).order(created_at: :desc)
person Stephen M    schedule 14.10.2017

Если вы правильно настроите ассоциации, это тривиально:

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 %>
person max    schedule 14.10.2017