尝试用同名重新创建已删除的聊天频道,依然失败

继续讨论 尝试用相同名称重新创建已删除的聊天频道失败

此错误在链接的帖子中已报告,但对我来说似乎仍然存在。我使用的是最新版本,昨天进行了 git pulllauncher rebuild

尝试将新聊天频道命名为任何先前使用过的聊天频道名称时,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”时,由于 slug 上的唯一性约束失败,我遇到了相同的 500 错误。

我不确定如何安全地删除已删除 ChatChannels 的(索引?)slug,但我愿意尝试一下。


可能相关:此问题也影响 slug,但似乎不是同一个问题:Attempt to recreate deleted chat channel with same name fails

2 个赞

我刚才测试了以下步骤,没有遇到问题:

  1. 创建一个名为“whiskers”,别名为“whiskers”的频道。
  2. 删除频道。
  3. 创建一个名为“whiskers”,别名为“whiskers”的频道。

这可以正常工作。

当频道被删除时(第 2 步),别名会自动更改为唯一的名称。但由于您在该更改引入之前删除了频道,因此旧的别名可能仍然存在。

您可能可以通过 rails 控制台手动更新已删除频道的别名,但我不知道正确的命令是什么。我会问一下。

另外请注意,频道别名现在可以独立于频道名称进行编辑,因此作为一种变通方法,您也可以在今天创建一个具有所需名称的频道,并选择一个不冲突的其他别名。

2 个赞

这完全出乎意料。

我们不会删除频道,我们只会将其软删除。因此,它们应该仍然在这里,并且 deleted_at 列已填充。

如果在控制台中运行此命令,您会得到什么结果?

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

我可以确认,在我的实例上,这个测试也对我有效,我的实例是完全最新的。

我认为问题在于数据库中的某个地方残留了一个本应被删除但未被删除的 slug,这可能是由于先前版本中的一个 bug 造成的,而该 bug 现在已被修复。此实例仅启用了聊天功能 17 天,因此任何 bug 都必须在此时间范围内存在。

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>

因此,要清除旧的已删除频道 slug,请执行类似以下操作:

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,但它使我能够看到已删除的实例并将它们的 slug 重命名为您的代码片段中的样子。

我可以确认这已修复。我同意 @j.jaffeux 的观点,这不太可能影响很多用户,所以我认为在此线程中提供一个 Rails 控制台修复就足够了。

3 个赞

很高兴 Marcus 的问题得到了解决。现在关闭此话题。

2 个赞

当我尝试创建一个新频道(命名为“general”,slug 也相同)时,日志中出现以下错误(前端没有任何反应)。

未显示“已关闭”频道。

我过去可能有一个 general 频道 - 并可能将其删除了(它是默认的吗?)

无法用另一个随机 slug 重现(创建 > 删除 > 创建工作正常)。

处理异常应用程序中间件中的异常失败:ActiveRecord::RecordNotUnique : PG::UniqueViolation: ERROR:  duplicate key value violates unique constraint "index_chat_channels_on_slug"
DETAIL:  Key (slug)=(general) already exists.

我已将您的帖子移至此处,以便将报告分组在一起。:+1:

上面的解决方法是否也适用于您的情况?

OP 中的解决方法,不行,没用。

这个对我来说似乎也没用。

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

OP 问题解决方法在此帖:

2 个赞

我试过这些,我共享的代码块就是关于这个的。

我在 rails 中未能运行这些命令。

也许我在这里做错了什么?

编辑:为了说清楚,建议的解决方法在使用查找频道时出现了同样的错误

[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 个赞