Rails 5: Как упорядочить модели по связанному атрибуту модели и выделить их - PullRequest
0 голосов
/ 17 января 2019

У меня есть область в рельсах, которая должна упорядочить набор разговоров по последнему атрибуту сообщения чата созданного_сети. Вот так:

class Conversation < ApplicationRecord
    has_many :chat_messages, -> { order(created_at: :asc) }, dependent: :nullify do
      def last_from_user
        from_user.order("created_at ASC").last
      end

      def last_delivered_from_user
        from_user.order("delivered_at ASC").last
      end

      def last_from_agent
        from_agent.order("created_at ASC").last
      end
    end

    default_scope { joins(:chat_messages).order("chat_messages.created_at desc").distinct }
end

Когда, например, организация с идентификатором 4 получает новое сообщение, я ожидаю, что порядок будет:

[4,1,2,3]

Тем не менее, я получаю:

[1,2,3,4]

если я удалю отдельный метод, подобный этому:

class Conversation < ApplicationRecord
    default_scope { joins(:chat_messages).order("chat_messages.created_at desc") }
end

Разговоры упорядочены в порядке, но дублируются: [4,1,2,3,4]

моя модель chat_message выглядит так:

    class ChatMessage < ApplicationRecord

      # Associations
      # ------------------------------------------------------------

      belongs_to :conversation
    end

Я не могу использовать «уникальный» метод, потому что это сделает невозможным правильную работу нумерации страниц.

Однако, когда разговор имеет более одного сообщения, «отдельный» метод портится с порядком. эта область возвращает разговоры в том порядке, в котором они были созданы, а не в порядке, который мне действительно нужен.

1 Ответ

0 голосов
/ 17 января 2019

Если мы удалим Rails и просто посмотрим на SQL, то понятнее. У вас есть классическая проблема SQL - попытка получить список, отсортированный по максимальному или минимальному значению на основе объединения.

Вы выполняете запрос, подобный этому:

SELECT conversations.*
FROM conversations
INNER JOIN chat_messages
  ON chat_messages.conversation_id = conversations.id
ORDER BY chat_messages.created_at desc

И вы получите обратно по строке для каждой пары разговоров и chat_messages . Вот почему у вас есть дубликаты.

Вы не можете использовать distinct с этим.

SELECT conversations.*
FROM conversations
INNER JOIN chat_messages
  ON chat_messages.conversation_id = conversations.id
ORDER BY chat_messages.created_at desc

ERROR 3065 (HY000): Expression #1 of ORDER BY clause is not in SELECT list,
references column 'test.chat_messages.created_at' which is not in SELECT list;
this is incompatible with DISTINCT

Если вы используете select distinct conversations.*, chat_messages.created_at, вы вернетесь туда, откуда начали.

Я не уверен, что делает .distinct, но это, вероятно, должно вызвать исключение.


Вместо этого избавьтесь от дубликатов с помощью group by conversation.id. Теперь, когда у вас есть сгруппированный запрос, вы можете order by max(chat_messages.created_at) desc.

select c.*
from conversations c
join chat_messages cm
  on cm.conversation_id = c.id
group by c.id
order by max(cm.created_at) desc

Переводя это в Rails ...

Conversations
  .joins(:chat_messages)
  .group(:id)
  .order("max(chat_messages.created_at) desc")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...