首先,非常感谢您的帮助!不过这确实是一个有趣的 bug。
问题是,我可能需要通过数据库来修改用户名,因为相关的路由不可用:![]()
您能提供一个查询语句吗?
我认为这不可行,因为那样会禁止希腊语中许多以 Σ 开头的名字(而且实际上会导致这些用户的 Facebook 登录失效)。我能否禁止某个特定的正则表达式模式?这样就能确保 Σ 至少出现在末尾。
首先,非常感谢您的帮助!不过这确实是一个有趣的 bug。
问题是,我可能需要通过数据库来修改用户名,因为相关的路由不可用:![]()
您能提供一个查询语句吗?
我认为这不可行,因为那样会禁止希腊语中许多以 Σ 开头的名字(而且实际上会导致这些用户的 Facebook 登录失效)。我能否禁止某个特定的正则表达式模式?这样就能确保 Σ 至少出现在末尾。
另一位成员也注册了完全相同的问题。我想说明的是,对我们而言,这并非边缘案例。实际上,有成千上万个希腊语名字在末尾使用 Σ(或 ς)。
此外,由于我们的主要用户群体年龄超过 40 岁,许多成员在 Facebook 上的名字是全大写的(
),因此当他们使用 Facebook 登录时,名字会被复制到用户名字段中……
我不必担心 Postgres。在 SQL 中,我们应始终与 username_lower 进行比较,而不依赖 LOWER(),因为 username_lower 不仅仅是用户名的全小写版本。我们还应用了 Unicode 规范化。
我同意。目前为止,为 User.normalize_username 添加一个变通方案就足够了。Ruby 的 bug 讨论中已经有一些相关言论,看来并没有简单的解决方案。不过,我们很幸运,因为我们需要做的只是检查用户名中的最后一个字符。这比在整个句子中进行检查要容易得多。
那么……这个用户名会如何处理呢?
大写:ΧΡΗΣΤΟΣ_ΠΑΝΑΓΙΩΤΑΚΟΠΟΥΛΟΣ
小写:χρηστος_παναγιωτακοπουλος 或 χρηστοσ_παναγιωτακοπουλος
NodeJs 能正确处理这种情况,但如果只检查用户名的最后一个字符,问题仍将存在。
(几乎所有希腊语男性名字——包括名和姓——都以 Σ 结尾)
没错。不过,这应该比完整实现容易得多,因为我们只需要处理某些符号,比如下划线、连字符,可能还有数字?这应该是可行的。
我知道我偏离了关于这个特定 Bug 的讨论,但一想到这个问题,我就无法忽视它本是可以避免的。
我发现 Discourse 中有些 API 路由通过 userId 引用用户,而另一些则通过 username 引用。这难道不应该更加一致吗(倾向于使用 userId)?
或许可以像现在处理分类/标签那样实现:在 URL 中同时包含用户名和 userId,例如:https://meta.discourse.org/u/chrispanag/4387
只是一个小想法 ![]()
这将需要一次清理工作,我确实见过一些 LOWER() 调用。
多年来这个问题一直存在:Update quotes and mentions when username is changed - #10 by sam
早在 2016 年,@eviltrout 就反对这样做,不确定他现在的立场如何。
无论如何,我在 Discourse 的这个 PR 中提供了一个变通方案:
它将通过将所有以西格玛(sigma)开头的用户名转换为小写,来解决 Facebook 新注册的问题。这意味着你只需要将 Spiros 的用户名以及其他带有词尾西格玛的用户名改为小写,问题就能从长远上得到解决。
(等待合并 PR)
非常感谢 @sam!你的帮助巨大。
有没有办法通过 Rails 控制台来操作?(因为该用户已损坏,无法通过管理面板进行操作……)
是的,这应该能解决问题。
./launcher enter app
rails c
u = User.find_by(username: 'ΣΠΥΡΟΣ')
u.username = 'σπυρος'
u.username_lower = 'σπυρος'
u.save!
我仍然不太喜欢到处使用 ID,但我理解在很多情况下这样做是合理的。
在这些情况下,我更倾向于使用类似 id-username 的格式,其中 username 可以是任何能放在 URL 中的内容。即使路由器忽略它也没关系。但至少当分享链接时,你就能知道链接指向的是什么。
关于 PostgreSQL,看起来设置正确的排序规则可以解决该问题:
➜ discoursesmall git:(master) psql -d discourse_development
psql (13.1 (Ubuntu 13.1-1.pgdg20.10+1))
输入 "help" 以获取帮助。
discourse_development=# SELECT lower('ΣΠΥΡΟΣ');
lower
--------
σπυροσ
(1 行)
discourse_development=# SELECT lower('ΣΠΥΡΟΣ' COLLATE "und-x-icu");
lower
--------
σπυρος
(1 行)
来源:PostgreSQL: Re: BUG #15805: Problem with lower function for greek sigma (Σ) letter
显然还有其他 Unicode 字符具有类似的转换,例如:‘ß’ → ‘SS’(德语)。
研究 Discourse 如何处理这些字符会很有趣……
此外,你也可以查看这个资源:
就我个人而言,我非常推崇 Stack Overflow 的用户路由风格:
https://stackoverflow.com/users/17174/sam-saffron
在 Discourse 中,这相当于:
https://meta.discourse.org/u/17174/sam-saffron
这种方式让你鱼与熊掌兼得。不过,我完全理解那些反对意见:“我不希望 URL 中出现 17174,因为用户名才是稳定的”。
话虽如此,我们现有的路由一直运行良好,只是每隔几年才会出现一些边缘情况。
我认为,至少在用户个人资料页面使用 ID 而不是用户名(或者两者都用,但如上文所述,仅依赖 ID)会更有帮助。这样,如果用户名出现问题,管理员就可以通过 Discourse 界面直接修改用户名,而无需在 Rails 控制台中运行命令。
我们只需要担心那些 JavaScript 和 Ruby 在将字符转换为小写时实现方式不同的情况。反之则无需担心。
德语小写字母 “ß” 转换为大写字母并没有统一规则。它可以是 “SS”、“SZ”,甚至是新的大写字母 “ẞ”(是的,这里有细微差别)。只有 “ẞ” 的反向转换是可行的,而 Ruby 和 JavaScript 都能正确处理这一点。
我认为我们应该采取以下措施:
LOWER(username),因为这本身就是一个糟糕的做法(例如,会导致 Unicode 规范化缺失)。不确定是否与此相关,但我们发现有一些用户的名称包含 Unicode 字符,这些名称分散在 /log 中。
ActionView::Template::Error (No route matches {:action=>"show", :controller=>"users", :username=>"ζηεδψ"}, possible unmatched constraints: [:username])