마지막 문자가 Σ인 Unicode 사용자 이름으로 프로필 페이지 로드 시 오류 발생

먼저 도움 주셔서 정말 감사합니다! 어쨌든 흥미로운 버그네요.

문제는 라우트가 사용 가능하지 않아서 데이터베이스를 통해 사용자 이름을 변경해야 할 수도 있다는 겁니다. :sweat_smile:

쿼리를 제공해 주실 수 있을까요?

그것은 불가능하다고 생각합니다. 그렇게 하면 그리스에서 Σ로 시작하는 많은 이름들이 금지되어 해당 사용자의 Facebook 로그인이 사실상 깨질 테니까요. 특정 정규식 패턴을 금지할 수 있을까요? 그러면 Σ가 적어도 끝부분에 위치하도록 보장할 수 있을 것 같습니다.

1개의 좋아요

다른 회원 한 명이 정확히 동일한 문제로 가입했습니다. 제가 여기서 강조하려는 점은, 우리에게는 이것이 경계 사례(edge-case)가 아니라는 것입니다. 그리스어 이름 중 이름 끝에 Σ(또는 ς)를 사용하는 이름이 실제로 수천 개나 됩니다.

그리고 불행히도, 우리의 주요 연령층(40세 이상)을 고려하면, 페이스북에 이름을 전부 대문자로 적어둔 회원들이 매우 많습니다 (:sweat_smile:) . 따라서 페이스북 로그인을 사용하면 이름이 사용자 이름 필드에 그대로 복사됩니다…

4개의 좋아요

Postgres에 대해서는 걱정하지 않으셔도 됩니다. SQL에서는 항상 username_lower를 비교해야 하며 LOWER()에 의존해서는 안 됩니다. username_lower는 단순히 사용자명의 소문자 버전이 아니기 때문입니다. 우리는 유니코드 정규화도 적용하고 있습니다.

동의합니다. 지금은 User.normalize_username에 우회 처리를 추가하는 것으로 충분할 것입니다. Ruby 버그 관련 토론에서 이미 논의가 이루어지고 있으며, 쉬운 해결책이 없어 보입니다. 하지만 우리는 운이 좋습니다. 사용자명의 마지막 문자만 확인하면 되기 때문입니다. 이는 완전한 문장에서 처리하는 것보다 훨씬 쉽습니다.

4개의 좋아요

음… 이 사용자 이름은 어떻게 처리될까요?

대문자: ΧΡΗΣΤΟΣ_ΠΑΝΑΓΙΩΤΑΚΟΠΟΥΛΟΣ
소문자: χρηστος_παναγιωτακοπουλος 또는 χρηστοσ_παναγιω타κοπουλος

NodeJs는 이를 올바르게 처리하지만, 사용자 이름의 마지막 문자만 확인한다면 문제가 지속될 것입니다.


(그리스어 남성 이름의 거의 모든 것, 이름과 성 모두, Σ로 끝납니다)

3개의 좋아요

맞아. 그래도 전체 구현보다는 훨씬 쉬울 거야. 밑줄이나 대시, 그리고 숫자 같은 특정 기호만 신경 쓰면 되니까. 충분히 해볼 만할 것 같아.

2개의 좋아요

이 특정 버그 논의에서 벗어나고 있다는 건 알지만, 이 문제를 생각할 때마다 이를 피할 수 있다는 사실을 무시할 수 없습니다.

discourse에서 사용자를 userId로 참조하는 API 경로와 username으로 참조하는 경로가 혼재되어 있다는 것을 발견했습니다. userId를 중심으로 더 일관되게 만들어서는 안 될까요?

예를 들어, 현재 카테고리/태그에서처럼 URL에 username과 userId를 모두 포함하는 방식(https://meta.discourse.org/u/chrispanag/4387)을 도입하는 건 어떨까요?

그냥 아이디어입니다 :sweat_smile:

2개의 좋아요

이 작업을 위해서는 정리 작업이 필요할 것입니다. LOWER() 호출이 몇 군데 있는 것을 분명히 확인했습니다.

4개의 좋아요

지난 몇 년간 이 문제가 계속 제기되어 왔습니다: Update quotes and mentions when username is changed - #10 by sam

2016년에 @eviltrout은 이에 반대했는데, 요즘 그의 입장이 어떻게 변했는지 확실하지 않습니다.

어쨌든, 저는 Discourse에서 이 PR으로 우회 해결책을 마련했습니다:

이 PR은 시그마(σ)로 시작하는 사용자 이름을 소문자로 변환하여 Facebook의 신규 가입 문제를 처리합니다. 즉, Spiros의 사용자 이름과 최종 시그마(ς)를 사용하는 다른 사용자들의 이름만 소문자로 수정하면 이 문제가 장기적으로 해결될 것입니다.

(PR 병합 대기 중)

4개의 좋아요

감사합니다 @sam! 정말 큰 도움이 되었습니다.

Rails 콘솔에서 이를 수행할 수 있는 방법이 있나요? (사용자가 손상되어 있어 관리자 패널을 통해 처리할 수 있는 방법이 없거든요…)

1개의 좋아요

네, 이렇게 하면 됩니다

./launcher enter app
rails c
u = User.find_by(username: 'ΣΠΥΡΟΣ')
u.username = 'σπυρος'
u.username_lower = 'σπυρος'
u.save!`
4개의 좋아요

여전히 모든 곳에 id를 사용하는 것을 좋아하지는 않지만, 그럴 만한 이유가 많은 경우들이 있다는 점은 이해합니다.

그런 경우에는 URL에 넣을 수 있는 어떤 값이든 username이라고 가정하고, id-username 같은 형태를 선호하겠습니다. 라우터가 이를 무시해도 괜찮습니다. 하지만 링크를 공유할 때, 어떤 것을 링크하고 있는지 최소한 감은 잡을 수 있을 테니까요.

6개의 좋아요

PostgreSQL의 경우, 적절한 정렬 규칙(collation)을 설정하면 문제가 해결되는 것으로 보입니다:

➜  discoursesmall git:(master) psql -d discourse_development
psql (13.1 (Ubuntu 13.1-1.pgdg20.10+1))
Type "help" for help.

discourse_development=# SELECT lower('ΣΠΥΡΟΣ');
 lower  
--------
 σπυροσ
(1 row)

discourse_development=# SELECT lower('ΣΠΥΡΟΣ' COLLATE "und-x-icu"); 
 lower  
--------
 σπυρος
(1 row)

출처: PostgreSQL: Re: BUG #15805: Problem with lower function for greek sigma (Σ) letter

7개의 좋아요

사실 ‘ß’ → ‘SS’ (독일어)와 같이 유사한 변환을 수행하는 다른 유니코드 문자들도 있습니다.

Discourse가 이러한 문자들을 어떻게 처리하는지 살펴보는 것도 흥미로울 것입니다.

또한 이 리소스도 확인해 보실 수 있습니다:

개인적으로 사용자를 위한 Stack Overflow 스타일의 라우팅을 매우 좋아합니다:

https://stackoverflow.com/users/17174/sam-saffron

Discourse에서는 다음과 같은 형태가 될 것입니다:

https://meta.discourse.org/u/17174/sam-saffron

이 방식은 케이크도 먹고 남도 먹는, 일석이조의 효과를 줄 수 있습니다. 물론 "URL 어딘가에 17174 같은 ID가 있는 것을 싫어합니다. 사용자 이름은 안정적이니까요"라는 반론도 충분히 이해합니다.

그럼에도 불구하고, 우리는 지금까지 기존 라우팅 방식으로 잘 유지해 왔으며, 몇 년에 한 번 정도 엣지 케이스가 발생하는 수준입니다.

5개의 좋아요

위에서 설명한 대로, 적어도 사용자 프로필 페이지에서는 사용자 이름 대신 id를 사용하거나(또는 둘 다 사용하되 id에만 의존하는 방식) 사용하는 것이 도움이 될 것 같습니다. 이렇게 하면 사용자 이름에 문제가 발생했을 때, 관리자(Admin)가 rails 콘솔에서 명령어를 실행할 필요 없이 Discourse UI를 통해 사용자 이름을 변경할 수 있습니다.

우리가 신경 써야 할 것은 소문자 변환 시 JavaScript와 Ruby 구현 방식이 다른 문자들뿐입니다. 반대 방향은 아닙니다.

독일어 소문자 "ß"를 대문자로 변환하는 규칙은 없습니다. “SS”, “SZ” 또는 새로운 대문자 “ẞ”(네, 미묘한 차이가 있습니다)가 될 수 있습니다. 이 과정을 역으로 수행하는 것은 "ẞ"에 대해서만 가능하며, 이는 Ruby와 JavaScript에서 모두 올바르게 작동합니다.


저는 다음을 수행해야 한다고 생각합니다:

  1. 즉각적인 문제를 해결하기 위해 @sam의 우회 방법을 병합합니다.
  2. LOWER(username)를 SQL 쿼리에서 제거합니다. 이는 단순히 잘못된™ 관행이기 때문입니다(예: 유니코드 정규화 누락).
  3. Ruby가 근본적인 문제를 수정하기를 바랍니다.
  4. 장기적으로: 루트에 사용자 ID를 추가하는 방안을 고려해 보겠습니다. 가장 어려운 부분은 인용과 멘션을 어떻게 처리할지 파악하는 것일 것입니다.
3개의 좋아요

관련이 있을지 확실하지 않지만, 유니코드 이름을 가진 몇몇 사용자의 기록이 /log에 흩어져 있습니다.

ActionView::Template::Error (No route matches {:action=>"show", :controller=>"users", :username=>"ζηεδψ"}, possible unmatched constraints: [:username])