未读计数显示“未读 (14)”,但 /unread 为空

在这个美好的周四早晨,我向大家提出一个有趣的难题。我发现我的网站上似乎出现了一个误报的未读计数器。

问题现象

顶部导航栏显示“未读 (14)”。但当我点击它并进入 /unread 页面时,没有任何未读主题列出。页面提示“没有未读内容”。

其他非管理员用户也遇到了同样的问题,只是未读数量各不相同。

在 iOS 上的 Discourse 应用中,我也看到了未读计数,即使实际上并没有未读主题,而且有时这个数字也不一致。

  • 平台:桌面网页版和 iOS 上的 Discourse 应用
  • 影响范围:多名用户
  • 站点eurth.org

我已进行的测试

我在安全模式下进行了测试:

  • https://eurth.org/?safe_mode=no_themes,no_plugins
  • https://eurth.org/unread?safe_mode=no_themes,no_plugins

问题依然存在,因此似乎并非由主题或客户端插件自定义引起。任何主题中都没有“耳语”(whispers),所以也不太可能是这个原因。

我也无法使用忽略功能,因为当未读列表为空时,/unread 页面上根本没有忽略按钮。

预期行为

如果导航栏显示“未读 (14)”,我应该在 /unread 页面上看到 14 个未读主题,或者至少看到一些可见的未读主题。

实际行为

  • 导航栏显示“未读 (14)”
  • /unread 页面为空
  • 没有可用的忽略按钮
  • 问题在安全模式下依然存在

问题

  • 是否有已知的方法可以重建或重置某个用户的未读状态?
  • 是否存在服务器端的不一致,导致即使 /unread 页面为空,未读计数仍然显示?

此前,我曾在 ask.discourse.org 上向 AI 咨询过该问题,最终它建议我在这里发布一个错误报告。

1 个赞

啊,幽灵未读消息问题又困扰你的网站了!

你最近是否更改过任何分类权限,或将某些话题移动到了安全分类?有某些操作改变了追踪状态。

既然其他用户也遇到同样的问题,难道不应该为所有用户重置吗?

我认为可以通过 Rails 控制台为所有用户修复此问题,但操作有点复杂,我需要先研究并测试一下。我现在正在用手机,但如果没人先提出解决方案,我稍后会尝试发布一个解决方法。

2 个赞

您好,

我们已知晓此漏洞并正致力于解决。对此我们也深感困扰 :wink:

3 个赞

是的。我们内部团队一直在开发一个类似于 Documentation 的分类,最近完成后已将其公开。

是的,确实如此。我的想法是先在自己身上测试,然后再为所有人修复。由于这是一个非常复杂的 bug(至少对我来说),在找到可行的解决方案之前,我不想让大家抱有过高的期望。

感谢您的信任。今天早上我注意到了 2026 年 5 月月度发布 v2026.05,以为它可能会修复该问题,但问题依然存在。我相信团队正在处理中。Discourse 真的很棒。

哦,天哪。:flushed_face: 老实说,我已经仔细阅读了所有相关的 bug 报告。有一小会儿,我甚至考虑直接从导航栏隐藏“未读”标签,然后干脆忽略它。但这并不能解决任何问题,对吧?看来它甚至在这里的 Meta 上也如影随形。

Screenshot 2026-05-28 at 13.52.18

1 个赞

好的,这个 Rails 脚本将作为全局“全部标记为已读”功能,强制将所有用户的未读计数重置为 0。因此,很遗憾,它会在清除虚假未读的同时,也清除所有合法的未读计数。我们可以在 Rails 中通过 SQL 命令实现这一点。但请注意,这并不能修复根本的 bug。另外,如果你手头有最近的备份,这是个不错的主意;不过我已在我的开发论坛测试过,脚本运行正常。

cd /var/discourse
./launcher enter app
rails c

粘贴以下完整代码块并按回车键执行:

sql = <<~SQL
  UPDATE topic_users
  SET last_read_post_number = topics.highest_post_number
  FROM topics
  WHERE topics.id = topic_users.topic_id
    AND COALESCE(topic_users.last_read_post_number, 0) < topics.highest_post_number
    AND topic_users.notification_level IN (2, 3, 4) -- 跟踪、关注、关注首帖
SQL

# 执行更新
result = ActiveRecord::Base.connection.execute(sql)
puts "成功清除全站 #{result.cmd_tuples} 个未读主题。"

# 强制客户端浏览器丢弃缓存状态并与数据库同步
MessageBus.publish("/topic-tracking-state", { clear: true })

用户可能需要强制刷新页面才能看到已清除的「未读」状态。