Как обновить список тем после внесения изменений?

Я реализовал пользовательскую кнопку в меню действий над постом, которая «выкидывает» пост из текущей ветки темы. Эта функция доступна автору темы и по сути выполняет операцию перемещения, но с меньшим количеством кликов. Операция на стороне бэкенда выполняется через новый пользовательский API-эндпоинт. Моя кнопка работает, за исключением того, что мне приходится вручную обновлять страницу, чтобы увидеть, что пост был перемещен.

После обновления пост выглядит так:

Мой вопрос: какой лучший способ обновить DOM с учетом этого изменения? В идеале я бы просто заменил пост на разделительный плейсхолдер, показанный выше, и избегал бы обновления всей страницы или всего списка тем.

Я представляю, что если мой API-эндпоинт вернет измененную тему, то мне останется только заменить/вставить новый пост в список тем.

Так что, похоже, это вопрос того, как работает управление состоянием внутри Discourse и как я могу подключиться к этому жизненному циклу.

Ищите в core (или в репозитории all-the-plugins) элементы, обновляющие MessageBus

Решение

Добавление этого кода в конец моего API-метода решило проблему:

MessageBus.publish("/topic/#{@topic.id}", reload_topic: true, refresh_stream: true)

Это должно обновить состояние не только для текущего пользователя, но и для любого другого, кто просматривает тему.

Исследование, приведшее к этому решению

Читайте дальше, если хотите проследить за моим анализом кодовой базы. Я делюсь этим для тех, кому это может быть полезно.

Что такое MessageBus?

Согласно объяснению Сэма о MessageBus (2013), похоже, что Ruby-код может публиковать и подписываться, тогда как JavaScript-код может только подписываться. Хорошо, значит, в рамках этой предлагаемой архитектуры мой серверный код будет отвечать за уведомление интерфейса.

Есть ли пример использования MessageBus, который мне подойдет?

Ни один из примеров плагинов не использует MessageBus.

GroupArchivedMessage.move_to_inbox! вызывает этот код, который отчасти близок к тому, что мне нужно, но используемый здесь тип кода мне не подойдет.

MessageBus.publish("/topic/#{topic_id}", { type: "move_to_inbox" }, group_ids: [group_id])

Этот код выглядит многообещающе.

MessageBus.publish("/topic/#{@topic.id}", reload_topic: true, refresh_stream: true)

Это было финальное решение, которое я выбрал.

Что происходит, когда браузер получает обновление?

Контроллер тем подписан на обновления темы, которую он в данный момент просматривает. Он запускает событие “post-stream:refresh”, которое инициирует обновление. Единственное, что я могу найти слушающим на другом конце, — это ScrollingPostStream, который привязывает метод _refresh к событию. Похоже, именно он фактически выполняет обновление.

Из этого я делаю вывод, что если бы я хотел обновить только текущего клиента, не отправляя обновление другим, я мог бы вызвать тот же код самостоятельно:

this.appEvents.trigger("post-stream:refresh", args)

И похоже, что это можно вызвать из любого компонента.

А как насчет оригинальной реализации move_posts? Публикует ли она в MessageBus?

При изучении ядра я вижу: метод контроллера тем move_posts() вызывает move_posts_to_destination(), который вызывает topic.move_posts(), который вызывает new PostMover(), а затем либо to_topic(), либо to_new_topic(). Эти методы не вызывают MessageBus, но они вызывают DiscourseEvent.trigger().

Я вызываю topic.move_posts() из своего пользовательского API-метода. Таким образом, мой код обращается напрямую к модели, минуя любую существующую логику контроллера:

new_topic = topic.move_posts(current_user, [post.id], {title: title, category_id: category_id})

В моем случае move_posts_to() вызывается как последний шаг в последовательности, который выполняет следующее:

DiscourseEvent.trigger(
  :posts_moved,
  destination_topic_id: destination_topic.id,
  original_topic_id: original_topic.id,
)

DiscourseEvent, похоже, не имеет ничего общего с MessageBus. Возможно, он используется только для внутренних жизненных циклов внутри сервера?

Таким образом, я прихожу к выводу, что MessageBus обычно не публикуется при перемещении темы.

Ох. Извините. Это немного удивительно! Думаю, мне следовало направить вас к ядру (core)! У меня есть плагин, который использует его, но он не является публичным, и он использует MessageBus для кастомной модели.

Не уверен, но, думаю, вам, вероятно, не нужен reload topic (если только не меняются данные, которые не отображаются без изменённых атрибутов?), но у меня в плагине есть несколько мест, где, как мне кажется, это могло бы решить проблему!