플러그인에서 user_guardian.rb 오버라이드 (포크 불필요!)

안녕하세요, 초보 질문이라 죄송합니다. 문서를 읽었긴 했는데, 좀 더 구체적인 안내가 필요합니다.

Discourse를 포크해서 제 나름의 수정을 했고, 이제 이걸 기반으로 직접 배포를 하고 싶습니다. 기여 가이드에서는 수정 방법과 PR 제출 과정을 안내하고 있지만, 제 경우에는 PR을 올리고 싶지 않습니다. 그저 제 작은 수정 사항을 반영해 Discourse 설치를 구동시키고 싶은 것이죠. 생각으로는 이 줄을 제 저장소로 바꾸면 될 것 같았습니다:

그렇게 변경하고 설치를 진행했는데, 제가 한 수정 사항이 반영되지 않아서 분명 뭔가 잘못하고 있는 것 같습니다. 혹시 아이디어가 있으신가요? 감사합니다!

수정:
투명성을 위해, 그리고 혹시 더 쉬운 방법이 있을 수 있으니 공유합니다. 제가 하려는 것은 익명 사용자가 익명 모드로 진입했을 때 사용자 이름과 사용자를 변경할 수 있도록 하는 것입니다. 이 줄에서 false를 true로 바꾸면 됩니다:

더 나은 방법이 있다면 기꺼이 듣고 싶습니다. 하지만 제가 활성화해야 할 것은 이것뿐입니다. 저는 Python과 Java, 그리고 다른 백엔드 기술에 익숙하지만, Ruby/JavaScript/HTML 등은 전혀 모릅니다.

수정2:
다른 곳에서 본 게시글에 따라 app.yml을 다음과 같이 업데이트했습니다:

run:
- exec:
 cd: /var/www/discourse
 cmd:
    - sudo -u discourse git remote set-url origin https://github.com/my/forked/discourse.git
    - sudo -u discourse git fetch origin
    - sudo -u discourse git checkout origin/master

앱을 다시 빌드한 후에도 여전히 문제가 해결되지 않았습니다. 정상적으로 실행되긴 하지만, 제 수정 사항이 존재하지 않는 것 같습니다.

변경 사항을 플러그인으로 묶어서 대신 사용하는 것이 불가능합니까?

그렇게 한 사람들은 모두 크게 후회했습니다. 그리고 여기서 도움을 받기도 어렵습니다.

무엇을 하든 플러그인으로 하세요.

알겠습니다. 플러그인으로 이렇게 하는 방법에 대해 혹시 아이디어가 있으신가요?

@leighno5 님, 안녕하세요.

개인 경험을 바탕으로 말씀드리자면, Ruby와 Rails를 충분히 이해하여 Discourse 플러그인을 쉽게 작성하거나(또는 어떤 Rails 클래스든 수정할 수 있을 정도) 익숙해진다면, 님이 현재 포크에서 하려는 일을 Ruby 플러그인으로 하는 것이 훨씬 쉽습니다.

반대로, Rails와 Ruby를 Discourse 플러그인을 작성할 정도로 충분히 이해하지 못한다면, 제 경험상 Discourse를 포크하여 코어에 손을 대는 것은 "잘못된 방향"입니다.

비유하자면 이렇습니다(이 단순한 비유로 죄송합니다):

“누군가가 걷는 것이 어렵다고 판단하여, 대신 달리기 결정을 내린 경우입니다.”

설명해 드리겠습니다. 괜찮으시다면요:

Rails 애플리케이션 개발을 시작하기 전(Discourse와는 무관하게), 그리고 Discourse 플러그인을 작성하려 했을 때 저는 약간 길을 잃었고, 아마도 Discourse에 대해 조금 불만도 있었을 것입니다. 처음에 골프공을 치고자 할 때와 비슷합니다. 공이 직진하지 않고 페어웨이 중앙에 공을 두는 데 많은 노력이 듭니다. Discourse를 포크하는 것은, 짧은 아이언으로 칩샷과 퍼팅을 할 수 있을 때조차도 연습장에서 드라이버를 꺼내 드는 것과 같습니다!

저는 Discourse 해킹에서 한동안(수개월) 쉬면서, 실제로 여러 개의 Rails 애플리케이션을 처음부터 구축하는 작업을 했습니다. 그리고 나서(그리고 오직 그때) 비로소 Rails에 대한 몇 가지 “직관적인” 지식을 갖추기 시작했습니다. 그 후, Discourse를 수정하기로 결심했을 때(현재 저는 Discourse 프로덕션 환경에서 제가 작성한 6개의 커스텀 플러그인을 운영 중입니다), 모든 것이 직관적으로 느껴졌고 Ruby 코어를 수정하는 플러그인들은 너무 쉬워졌습니다.

Ruby는 매우 유연합니다. 어떤 클래스든, 어떤 객체든 오버라이드할 수 있습니다. Ruby의 모든 측면을 재정의할 수 있습니다. 몇 가지 경험을 쌓으면, "와, Ruby가 이렇게 유연하고(강력하고) 강렬하다는 건 몰랐네"라고 느끼기 시작하며, Ruby와 Rails로 슈퍼맨처럼 날아다니게 되어 "위험한 존재"가 되기 시작합니다. 그때 우리는 Ruby와 Rails 여정의 시작점에 있는 것이지, 끝점에 있는 것이 아닙니다!

2020년에 쌓은 Ruby와 Rails 지식을 바탕으로, 지금 제가 아는 것을 안다면, 님이 제안하듯 Discourse를 포크하여 Ruby와 Rails 코어에 변경 사항을 가하는 일은 절대 하지 않을 것입니다. Ruby 클래스의 기본 개념과 메타 프로그래밍의 기본을 이해한다면, 플러그인으로 Ruby 클래스를 오버라이드하고 수정하는 것은 너무도 쉽기 때문입니다.

솔직하게 말씀드리면 죄송하지만, 제 말은 이렇습니다. 누군가가 몇 가지 사소한 Ruby 변경 사항을 위해 Discourse 코어를 해킹해야 한다고 생각한다면, 그 사람은 Ruby와 Rails를 충분히 이해하지 못하고 있다는 뜻입니다. 만약 충분히 이해하고 있다면, 코어를 해킹하지 않고 클래스를 오버라이드하는 간단한 플러그인을 작성하고 몽키 패칭(monkey-patching)을 즐겼을 것이기 때문입니다.

반면, 만약 제가 Discourse의 EmberJS를 React와 Ant Design으로 교체하는 것과 같이 미친 짓을 하고 싶고 불행해지고 싶다면, 포크하는 것이 유일한 방법일 것입니다! 그러나 제 생각에는 "Discourse"는 "JavaScript 라이브러리"로 정의되는 것이 아닙니다. Discourse는 핵심 개발 팀(사람들)의 기술, 디테일에 대한 관심, 고객 서비스, 오픈 소스 코드 개발에 대한 팀 접근법, SPA 기능 파이프라인, 그리고 그들의 모든 노력으로 정의됩니다. Ember보다 Ant Design(React)이나 VueJS를 더 좋아할 수도 있다는 이유만으로 그 모든 지능을 버리는 것은 (제 생각에) 약간 미친 짓일 것입니다.

이것은 단순히 여기저기 Discourse 코어를 수정하려는 경우에도 더더욱 적용됩니다. 그렇게 하려고 포크하여 "사람들"을 버리는 것은 약간 "미친 짓"일 것입니다. 그 "사람들"이 바로 “진짜” Discourse(코드가 아닌)이기 때문입니다.

저는 2020년에 Ruby와 Rails를 배우며 겪은 개인적인 여정에 대해만 말씀드리고 있습니다. 이제 (기본적인 부분은) 쉬워지고 있고, 저는 "위험한 존재"가 되고 있습니다, LOL. 저는 “무엇이든 몽키 패칭으로 뚫고 나갈 수” 있지만, 이것이 항상 좋은 것은 아닙니다. 그리고 바로 이것이 Discourse 플러그인의 존재 이유입니다.

코어는 바위처럼 단단하게 유지하고, 플러그인으로 Discourse를 "몽키 패칭"하는 재미를 즐기세요.

이 글이 도움이 되길 바랍니다.

참고로, 이 답변을 작성하면서 님은 다음과 같이 작성하셨습니다:

이것은 제 주장을 어느 정도 증명하는 것 아닌가요?

Discourse에서 "플러그인"을 작성하는 것은 (한 차원에서는) "Ruby 코드"를 작성하는 것이며, 다른 사람들에게는 훨씬 더 깊은 곳(EmberJS)까지 영향을 미칩니다.

Discourse 플러그인 작성을 시작하기 전에, 님께는 가치가 없어 보일 수 있지만, 제 친절한 조언은 먼저 몇 가지 Ruby on Rails 앱을 개발해 보라는 것입니다. Ruby와 Rails를, 적어도 기본 개념을 익히면, 위에서 던진 질문에 대한 답을 스스로 찾을 수 있을 것입니다.

오늘 아침 저는 클라이언트와 3시간 동안 컨퍼런스 콜을 하며 Rails 앱, 검증, 모델 등을 논의했고, 그 후 통화에서 나온 액션 아이템 중 일부를 코딩하는 동안 휴식을 취하다가 님의 글을 읽었습니다.

제 생각에, Discourse 플러그인을 작성하기까지의 가장 짧은 경로는 먼저 Rails를 배우는 것입니다.

이 글이 도움이 되길 바랍니다!

좋은 시작점으로 다음을 추천합니다:

아니요, 정확히 맞으세요. 저는 루비(Ruby)에 대해 전혀 경험이 없기 때문에, 당연히 기분 나쁘게 생각하지 않았습니다!

플러그인 가이드를 보고 몇 번이나 읽었지만, 불행히도 루비에 대한 무지가 계속 답답함을 유발하고 있으며, user-guardian 파일의 그 작은 코드 부분을 덮어써서匿名用户가 이름을 변경할 수 있도록 하는 플러그인을 어떻게 작성해야 할지 전혀 감이 잡히지 않습니다. :confused:

@leighno5 님, 안녕하세요.

네, 이해합니다.

그 “HOWTO” 플러그인 주제들은 10년 이상의 Rails 및 Ruby 프로그래밍 경험(심지어 더 오래된 경우도 있을 수 있습니다)을 가진 매우 재능 있는 개발자들이 작성했습니다. 사실, 그분들 중 일부는 세계 최고의 Ruby 및 JS 개발자 중 한 명입니다.

저는 100% 확신합니다. 그분들은 모두 첫 번째 Discourse 플러그인을 작성하기 훨씬 전에 Rails와 Ruby를 배웠을 것입니다.

사실 Rails를 배우는 것은 그렇게 어렵지 않습니다. 하지만 몇몇 Rails 앱을 처음부터 끝까지 직접 구축하는 "실습 의식"을 실제로 거치는 것이 필요합니다. 단순히 유튜브 튜토리얼을 따라 하는 것(그것도 좋은 방법이지만)만으로는 부족하며, 데이터베이스 설정, 모델 생성, 컨트롤러 생성, 모델 유효성 검사 작성, 초기화자(initializer) 작성, 헬퍼 모듈 작성, 데이터베이스 마이그레이션(수정), 임베디드 Ruby 작업 등 직접 처리해야 하는 작업이 포함된 작동하는 애플리케이션을 실제로 구축해야 합니다.

사실 매우 재미있으며, 플러그인을 작성하는 데 실제로 편안함을 느끼기 위한 "가장 짧은 경로"입니다(Ember 부분은 제가 직접 다루지 않지만, Rails 쪽은 정말 좋아합니다)!

또한, Rails 콘솔을 반드시 배워야 합니다! Rails 콘솔은 정말 재미있으며, 저는 매일 즐겁게 사용하고 있습니다!

오늘, 제 최애 클라이언트와 AnyDesk를 하고 있었는데, 그는 "이 새로운 재고(Inventory) 뷰를 만들어 줄 수 있을까요?"라고 물었습니다. 그는 제가 모든 과정을 수행하는 것을 지켜보고 싶어했습니다. 우리가 그것을 작동시키기 시작한 후, 통화 마지막에 그는 "수십 년 전이라면 몇 주가 걸렸을 일을 Rails로 30분 만에 해내셨네요!!"라고 말했습니다. 정말 대단합니다, @leighno5 님. 도전해 보세요!!

Rails를 배우신 후, Discourse 플러그인을 작성하는 것이 꽤 쉽다는 것을 "WOW"라고 감탄하게 될 것입니다. 적어도 Rails와 Ruby 부분은요!!

도움이 되셨기를 바랍니다.

기존의 Customization > Plugin 코드를 확인해 보세요. 현재 그런 코드가 아주 많이 있으니 참고할 예시가 풍부합니다. 기존 구현을 읽는 것을 건너뛰지 마세요. 이를 활용할 수 있습니다.

하나의 메서드를 오버라이드하려는 것 같네요. 이는 plugin.rb 파일에서 해당 메서드를 재정의하는 것만으로 해결됩니다(모듈별로 개별 파일로 분리하는 것이 모범 사례라고 할 수 있지만, 메서드 하나만 수정하는 경우에는 그럴 필요가 없어요!).

이미 보여주신 친절함에 더 얹혀서 제 무지를 드러내는 건 아닌지 걱정되지만, 이 부분을 조금 더 자세히 설명해 주실 수 있을까요? 아니면 모듈을 오버라이드한 다른 사례를 알고 계신다면 링크를 주셔도 감사하겠습니다. "rtfm(문서 먼저 읽어보세요)"이라는 말에 전혀 반감이 없지만, 다양한 튜토리얼과 문서를 꼼꼼히 살펴봤음에도 디스코스가 어떻게 동작하는지 이해하지 못해 답답합니다. 그리고 네, 이런 기본적인 질문은 제가 노력을 덜 기울인 것처럼 보일 수 있다는 걸 알지만, 실제로는 그렇지 않다고 약속합니다!

PostGuardian에 메서드를 정의한 예시를 하나 보여 드리겠습니다:

https://github.com/paviliondev/discourse-topic-previews/blob/f4332f9742a37827fd6364b2365c45524f1e7faf/lib/guardian_edits.rb#L10

UserGuardian의 경우에도 기존 메서드 이름을 사용하여 유사한 작업을 수행하면 오버라이드할 수 있습니다.

간단한 해결책 (단단하지는 않지만 동작하게 만드는 방법):

원래 메서드 코드를 그대로 작성한 후 수정 사항을 적용하면 됩니다. 단점: Discourse에서 코드를 변경할 경우 플러그인으로 인해 인스턴스가 깨질 수 있습니다.

고급 해결책 (더 견고한 해결책):

보너스 포인트를 얻으려면 super를 사용해 원래 메서드를 상속할 수 있지만, 여기서 자세히 설명하지는 않겠지만 이것이 항상 동작한다고 보장되지는 않습니다. 다만 이는 최선의 관행입니다. 그렇게 하면 Discourse에서 해당 메서드에 대한 업데이트가 항상 반영되므로 플러그인을 수정할 필요가 없게 됩니다.

Discourse는 플랫폼입니다. 이를 익히는 데 시간이 걸립니다. 차근차근 진행해 보세요.

제가 걱정했던 바로 그 부분이네요. 다음 단락에서 언급된 고급 메서드는 사용 가이드에 포함되어 있나요? 기존 플러그인에서 이 메서드가 어떻게 사용되는지 보여주는 좋으면서도 간단한 예시가 있나요? 새로운 플러그인을 만들 때 (복사하여) 사용할 수 있는 예시 말입니다.

지금은 고급 방법에 대해 걱정하지 않아도 됩니다. 일단 동작하게 만드는 데 집중하세요. Ruby on Rails에 대한 일반적인 내용은 온라인 가이드에서 따로 찾아볼 수 있습니다. 이건 Discourse나 이 포럼의 주제에서 약간 벗어난 내용입니다. 참고만 해주세요.

네, 감사합니다! 제가 짧은 플러그인을 작성한다고 가정해 보겠습니다. 제가 이해한 대로라면, 업그레이드할 때마다 코어 코드를 확인하고 관련 코어 코드가 변경되었다면 플러그인을 다시 작성해야 하는 것이 맞나요? 감사합니다.

맞습니다. 가끔씩 확인하시고, 특히 문제가 생기기 시작할 때는 꼭 점검하세요. 가디언 코드는 사이트 인증을 담당하기 때문에 조금 더 중요하므로 주의를 기울이세요.

또 다른 해결책은 테스트 케이스(별명: 스펙)를 추가하고 이를 실행하는 자동화 작업을 설정하는 것입니다 … 하지만 이 방법은 좀 더 복잡합니다!

추가 점수 과제로, 플러그인의 테스트를 실행하도록 travis-ci.org를 설정하여 문제가 발생하면 미리 알 수 있도록 하는 것입니다.

절대 가볍게 여길 일이 아닙니다. 로그인/신규 계정 생성 모달을 변경하고, Twitter 이미지를 제거하고 싶습니다. 아마 후자가 더 좋은 첫 번째 프로젝트가 될 것 같습니다. 감사합니다.

이 글을 보시고 저처럼 막막하셨던 분들을 위해, 의도한 대로 동작하도록 만든 제 코드를 아래에 공유합니다. 기존 파일은 수정하지 않았습니다. 단순히 plugin.rb라는 새 파일을 생성하고 아래 내용을 넣었습니다:

# about: Allows users in Anonymous Mode to change their usernames
# version: 0.1


require_dependency 'guardian'
require_dependency 'guardian/user_guardian'

class ::Guardian
end

module ::UserGuardian
  def can_edit_username?(user)
    return false if SiteSetting.sso_overrides_username?
    return true if is_staff?
    return false if SiteSetting.username_change_period <= 0
    return true if is_anonymous?
    is_me?(user) && ((user.post_count + user.topic_count) == 0 || user.created_at > SiteSetting.username_change_period.days.ago)
  end


  def can_edit_name?(user)
    return false unless SiteSetting.enable_names?
    return false if SiteSetting.sso_overrides_name?
    return true if is_staff?
    return true if is_anonymous?
    can_edit?(user)
  end
end

이 코드는 Discourse 코어의 user_guardian.rb 클래스를 오버라이드하여, 사용자가 익명 계정에서 사용자 이름과 이름을 변경할 수 있도록 합니다.

여기 있는 제 코드와 Discourse 코어의 user_guardian.rb를 비교해 보면, 제가 건드릴 필요가 없었던 다른 부분들이 많이 있어 그대로 두었습니다. 제가 필요한 것은 can_edit_username과 can_edit_name 메서드 두 개에서 일부 반환 값을 false에서 true로 변경하는 것이었고, 이를 통해 제가 원하는 결과를 얻을 수 있었습니다.

물론 개선할 부분이 있을 수 있고, 여기와 다른 곳의 링크된 게시글을 읽으면서 파악할 수 있는 모범 사례가 있을 수도 있지만, 저처럼 Ruby를 처음 접하는 초보자라면 코어에서 아주 간단한 부분만 조정하고 싶을 때, 이 글은 필요한 작업을 수행하기 위한 최소한의 작동 예시를 보여줍니다.

이 스레드에서 저에게 인내심을 갖고 격려와 도움을 주신 모든 분들께 감사드립니다. 특히 이전에 다른 게시글에서 실제로 도움을 주신 @merefield님께 감사드립니다.

ㅋㅋ

초기 아이디어에서 디스코urs 전체를 포크하고 이런 간단한 작업들을 위해 메인 브랜치를 포기하기까지 정말 많이 변했네요.

잘했어요 :slight_smile:

Install Discourse on Ubuntu or Debian for Development 의 전체 경로를 따랐나요, 아니면 단순히 프로덕션 사이트를 작업하면서 그저 잘 되기를 바랐나요?