Попытка воссоздать удалённый чат-канал с тем же именем (всё ещё) не удаётся

Продолжение обсуждения из темы Попытка воссоздать удалённый чат-канал с тем же именем завершается ошибкой:

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

При попытке назвать новый чат-канал именем любого ранее использовавшегося чат-канала в консоли JS возникает ошибка 500.

В логах ошибок Discourse я вижу:

Failed to handle exception in exception app middleware : ActiveRecord::RecordNotUnique : PG::UniqueViolation: ERROR:  duplicate key value violates unique constraint "index_chat_channels_on_slug"
DETAIL:  Key (slug)=(sec-fhir) already exists.

В консоли Rails я вижу, что удалённые ChatChannels исчезли, но подозреваю, что где-то удалённый slug остался в индексе или в какой-то другой зависимости БД и не был удалён.

Это обходное решение у меня не работает: при попытке переименовать «foo2» в «foo» возникает та же ошибка 500 из-за нарушения ограничения уникальности на slug.

Не знаю, как безопасно удалить (индексированные?) slug удалённых ChatChannels, но готов попробовать.


Возможно, связано с этой проблемой, которая также затрагивает slug, но, похоже, это не та же самая проблема: Attempt to recreate deleted chat channel with same name fails

2 лайка

Я только что протестировал это и проблем не возникло:

  1. Создать канал с именем “whiskers” и слагом “whiskers”
  2. Удалить канал
  3. Создать канал с именем “whiskers” и слагом “whiskers”

Это сработало.

При удалении канала (шаг 2) слаг автоматически меняется на уникальный. Но так как вы удалили свой канал до того, как это изменение было внедрено, старый слаг, возможно, всё ещё сохраняется.

Вы, вероятно, можете вручную обновить слаг для удалённого канала через консоль Rails, но я не уверен, какая именно команда для этого нужна. Я уточню.

Обратите также внимание, что слаг канала теперь можно редактировать независимо от имени канала, поэтому в качестве обходного решения вы можете сегодня создать канал с нужным именем и выбрать другой слаг, который не будет конфликтовать.

2 лайка

Это очень неожиданно.

Мы не удаляем каналы полностью, а только помечаем их как удалённые (soft delete). Значит, они всё ещё должны быть здесь, с заполненным полем deleted_at.

Если вы выполните это в консоли, результат будет пустым?

ChatChannel.find_by(slug: "sec-fhir")
[1] pry(main)> ChatChannel.find_by(slug: "sec-fhir")
=> nil

Могу подтвердить, что этот тест также работает у меня на моём экземпляре, который полностью обновлён.

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

1 лайк

Не могу воспроизвести это ни при каких обстоятельствах. После создания резервной копии базы данных попробуйте выполнить эти команды в консоли Rails. Хотя это кажется удивительным.

[1] pry(main) > DB.exec("DROP INDEX IF EXISTS index_chat_channels_on_slug;")
[2] pry(main) > DB.exec("CREATE UNIQUE INDEX index_chat_channels_on_slug ON chat_channels(slug);")

Я проверил, и это ожидаемое поведение, так как мы исключаем записи с заполненным полем deleted_at, даже при использовании find_by:

ChatChannel.find_by(slug: "sec-fhir")
  ChatChannel Load (0.4ms)  SELECT "chat_channels".* FROM "chat_channels" WHERE "chat_channels"."deleted_at" IS NULL AND "chat_channels"."slug" = 'sec-fhir' LIMIT 1
=> nil

Вместо этого вам нужно сделать следующее (добавив with_deleted):

ChatChannel.with_deleted.find_by(slug: "sec-fhir")
  ChatChannel Load (0.3ms)  SELECT "chat_channels".* FROM "chat_channels" WHERE "chat_channels"."slug" = 'sec-fhir' LIMIT 1
=> #<CategoryChannel:0x00007fc9bfb4abf0
 id: 124,
 chatable_id: 19,
 deleted_at: Wed, 15 Feb 2023 01:19:20.982181000 UTC +00:00,
 deleted_by_id: nil,
 featured_in_category_id: nil,
 delete_after_seconds: nil,
 chatable_type: "Category",
 created_at: Fri, 13 Jan 2023 01:46:43.730329000 UTC +00:00,
 updated_at: Wed, 15 Feb 2023 01:19:56.427647000 UTC +00:00,
 name: "test channel",
 description: "",
 status: "archived",
 user_count: 1,
 last_message_sent_at: Fri, 13 Jan 2023 01:46:51.130903000 UTC +00:00,
 auto_join_users: false,
 user_count_stale: false,
 slug: "sec-fhir",
 type: "CategoryChannel",
 allow_channel_wide_mentions: true,
 messages_count: 0,
 threading_enabled: false>

Чтобы очистить старый слоган удаленного канала, сделайте что-то вроде этого:

channel = ChatChannel.with_deleted.find_by(slug: "sec-fhir")
channel.update!(slug: "#{channel.deleted_at.strftime("%Y%m%d-%H%M")}-#{channel.slug}-deleted")

Возможно, нам понадобится миграция для исправления этого, @mcwumbly и @j.jaffeux?

2 лайка

Да, точно, забыл про with_deleted в этом случае :+1:

Предлагаю пока оставить ваш ответ здесь. Это должен быть редкий случай: удаление до исправления + желание создать заново с тем же именем.

4 лайка

Спасибо за информацию выше. Я не знал о with_deleted, но это позволило мне увидеть удалённые экземпляры и переименовать их слайги, как в вашем сниппете.

Я подтверждаю, что проблема исправлена. Я согласен с @j.jaffeux, что это, скорее всего, затрагивает не многих пользователей, поэтому, на мой взгляд, достаточно того, что в этой теме есть решение через консоль Rails.

3 лайка

Отлично, рад слышать, что у вас, Маркус, это решило проблему. Закрываю эту тему.

2 лайка

Когда я пытаюсь создать новый канал (с именем “general”, то же самое для слага), в логах появляется следующая ошибка (на фронтенде ничего не происходит).

Каналы со статусом «Закрытый» не отображаются.

Возможно, у меня раньше был канал с именем general — и я, вероятно, удалил его (является ли он каналом по умолчанию?).

С другим случайным слагом ошибка не воспроизводится (создание → удаление → создание работает без проблем).

Не удалось обработать исключение в промежуточном ПО обработки исключений приложения: ActiveRecord::RecordNotUnique : PG::UniqueViolation: ОШИБКА: дубликат значения ключа нарушает уникальное ограничение "index_chat_channels_on_slug"
ДЕТАЛИ: Ключ (slug)=(general) уже существует.

Я перенёс ваш пост сюда, чтобы все отчёты были сгруппированы вместе. :+1:

Подойдёт ли описанное выше решение и в вашем случае?

Обходное решение в оригинальном посте не сработало.

Это тоже, похоже, не сработало у меня.

[1] pry(main)>> ChatChannel.find_by(slug: "general")
NameError: uninitialized constant ChatChannel
from (pry):1:in `__pry__'

Решение проблемы автора первого поста находится в этом сообщении:

2 лайка

Я пробовал эти варианты, именно об этом и был мой общий блок кода.

Мне не удалось выполнить эти команды в Rails.

Возможно, я что-то делаю не так?

EDIT: чтобы было понятнее, предложенный обходной путь вызывает ту же ошибку при поиске канала:

[7] pry(main)> ChatChannel.with_deleted.find_by(slug: "general")
NameError: uninitialized constant ChatChannel
from (pry):7:in `__pry__'
2 лайка

Ладно, мне удалось решить проблему (по крайней мере, я так думаю).

Для меня это было довольно хлопотно, поэтому я поделюсь полным пошаговым решением.

cd /var/discourse && ./launcher enter app
rails c
DB.exec("UPDATE chat_channels SET slug = 'new' WHERE slug = 'old';")

Так что в вашей консоли Rails это будет выглядеть так:

[1] pry(main)> DB.exec("UPDATE chat_channels SET slug = 'new' WHERE slug = 'old';")
=> 1
[2] pry(main)> exit
root@discourse-app:~# exit
logout
➜  discourse git:(main) ✗ 

Теперь я могу создать новый канал с нужным slug.

Это правильный (или один из правильных) способ?

2 лайка

Приведенный выше обходной путь не работает из-за изменения пространства имен, которое мы внедрили несколько недель назад. ChatChannel теперь называется Chat::Channel.

1 лайк

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

2 лайка