プラグインで user_guardian.rb をオーバーライドする(フォーク不要!)

こんにちは、初心者向けの質問で申し訳ありません。ドキュメントは読みましたが、いくつかのアドバイスが欲しいです。

Discourse をフォークして独自の変更を加え、そこから独自にデプロイしたいと考えています。貢献に関するガイド では変更を加えて PR を提出する方法が説明されていますが、今回は PR を提出したくありません。単に小さな変更を加え、そこから Discourse のインストールを動かしたいだけです。そのためには、以下の行を自分のリポジトリに変更すればよいと思っていたのですが:

実際にそのように変更してインストールを試みましたが、反映されません。明らかに何か間違えているようです。ご助言があれば幸いです。ありがとうございます!

追記:
透明性のために、またもしもっと簡単な方法があるなら参考までに申し上げますと、私がやりたいのは、匿名モードに入った際に匿名ユーザーがユーザー名を変更できるようにすることです。これは以下の行の falsetrue に変更するだけで済みます:

もしより良い方法があれば、ぜひ教えていただきたいです。ただ、これを有効にするだけで十分です。私は 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

アプリを再構築してもまだうまくいきません。起動は問題ないようですが、変更が反映されていないようです。

変更をプラグインにまとめて、それを使うことはできないのでしょうか?

「いいね!」 5

それを行った全員が非常に後悔しています。また、ここではほとんどサポートを受けられません。

何をするにしても、プラグインとして実装してください。

「いいね!」 10

はい、プラグインを使ってこれを行う方法について何かご存知ですか?

@leighno5 さん、こんにちは。

私の個人的な経験に基づいた考えをお伝えしますと、あなたが「フォーク」で行おうとしていることを Ruby のプラグインとして実装する方が、Discourse 用のプラグインを簡単に書ける(あるいは任意の Rails クラスを修正できる)ほど Ruby と Rails を理解している場合、はるかに簡単です。

もし Discourse プラグインを書くのに十分なほど Rails と Ruby を簡単に理解できていないなら、私の経験上、Discourse をフォークしてコア部分をいじくり回すのは「誤った方向」だと言えます。

比喩を挙げるとすれば(単純な考えで申し訳ありませんが)、こうなります。

「歩くのが難しい人が、代わりに走ることに決める」

もしよろしければ、少し説明させてください。

私が Rails アプリケーションの作成(Discourse とは直接関係ありません)を始め、Discourse プラグインの作成を試みる前には、少し行き詰まっていました。また、Discourse に少しイライラしていたかもしれません。それは、初めてゴルフボールを打とうとするときのようでした。ボールは真っすぐ飛ばず、フェアウェイの中央に打つには多くの練習が必要です。Discourse をフォークすることは、ショートアイアンでチップショットやパットができるようになる前に、練習場でドライバーを振り回すようなものです!

Discourse のいじくり回しからしばらく(数ヶ月ほど)離れ、実際にゼロからいくつかの Rails アプリケーションを構築する仕事に集中しました。そして(その時だけ)、Rails に関する「直感的な」知識を身につけ始めました。その後、Discourse を修正することに決めました(現在は生産環境で私が作成した 6 つのカスタムプラグインを実行しています)が、すべてが直感的になり、Ruby コアを修正するプラグインも非常に簡単になりました。

Ruby は非常に柔軟です。あらゆるクラスやオブジェクトをオーバーライドできます。Ruby のあらゆる側面を再定義することも可能です。ある程度の経験を得ると、「なんて Ruby は柔軟で(そして強力な)んだ!」と驚き始め、スーパーマンのように Ruby と Rails で空を飛べるようになるため、「危険な存在」になり始めます。その時点では、Ruby と Rails の旅の始まりにすぎず、終わりではありません!

2020 年に得た Ruby と Rails の知識、つまり今の私が知っていることを基にすれば、あなたが提案しているように Ruby や Rails のコアを変更するために Discourse をフォークすることはありません。なぜなら、Ruby クラスの基礎とメタプログラミングの基礎を理解していれば、プラグインを使って Ruby クラスをオーバーライド・修正するのは非常に簡単だからです。

私が言いたいのは、直接的で申し訳ありませんが、Discourse のコアをいじって小さな Ruby の変更を加える必要があると思うなら、その人は Ruby と Rails を十分に理解していないということです。もし理解していれば、コアをいじるのではなく、クラスをオーバーライドする簡単なプラグインを書き、モンキーパッチングを愛するはずです。

一方、EmberJS を React と Ant Design に置き換えるような「狂気じみた」ことをして苦しまねばならない場合、フォークするしかありません!しかし、私の見解では、「Discourse」は「JavaScript ライブラリ」によって定義されるものではありません。Discourse を定義しているのは、コア開発チーム(人々)のスキル、細部への注意、顧客対応、オープンソースコード開発に対するチームアプローチ、SPA 機能のパイプライン、そして彼らのすべての努力です。Ant Design(React 付き)や VueJS を好むからといって、そんな脳力をすべて捨て去るのは(私の考えでは)少し狂気じみています。

単に Discourse のコアを少しだけ修正しようとしている場合も、これも全く同じことが言えます。それをするためにフォークして、「人々」を捨てるのは少し「おかしい」ことです。彼らこそが「本当の」Discourse(コードではない)なのですから。

これは私が 2020 年に Ruby と Rails を学んだ個人的な旅からの発言にすぎません。今は基礎が簡単になり、「危険な存在」になりつつあります(笑)。私は「何でもモンキーパッチでいじれる」ようになりましたが、それが常に良いこととは限りません。それが Discourse プラグインの存在理由です。

コアは岩のように固く保ち、プラグインを使って Discourse と「いじくり回る」のを楽しんでください。

お役に立てれば幸いです。

なお、この返信を書いている間に、あなたはこう書かれました:

これが私の主張を証明していると思いませんか?

Discourse での「プラグイン」作成は(あるレベルでは)「Ruby コード」の作成であり、他の人にとっては(EmberJS の面で)もっと深いものです。

Discourse プラグインの作成を始める前に、私の友好的なアドバイス(あなたにとって価値がないように見えるかもしれませんが)は、まずいくつかの Ruby on Rails アプリを開発することです。Ruby と Rails の道筋、少なくとも基礎を学んでください。その後、あなたは上記の質問に自分で答えられるようになるでしょう。

私の見解では、Discourse プラグインを書くための最短ルートは、まず Rails を学ぶことです。

お役に立てれば幸いです!

「いいね!」 5

始めるのに最適な場所はこちらです:

「いいね!」 3

いいえ、あなたの理解はまさにその通りです。私はRubyの経験がまったくないので、全く気にしないでください!

プラグインガイドは見て、何度か読み通しましたが、残念ながら私のRubyの無知がまだ悩みを招いています。user-guardian ファイル内のその小さなコードを上書きして、匿名ユーザーが名前を変更できるようにするプラグインをどう書けばよいか、全く見当もつきません。:confused:

「いいね!」 2

こんにちは @leighno5

はい、お気持ちよく理解できます。

あの「HOWTO」プラグイントピックは、10 年以上の Rails と Ruby のプログラミング経験を持つ(もしかしたらそれ以上かもしれません)非常に才能のある開発者たちによって書かれました。実際、彼らの一部は世界トップクラスの Ruby と JS 開発者です。

彼らが最初の Discourse プラグインを書く遥か以前から、Rails と Ruby を学んでいたことは 100% 確信しています。

実は Rails の学習はそれほど難しくないのですが、いくつかの Rails アプリをゼロから構築する「実践的な儀式」を体験する必要があります。単に YouTube のチュートリアルを追うだけでは不十分です(それも良いことですが)。データベースのセットアップ、自分自身のモデルの生成、自分自身のコントローラーの生成、モデルのバリデーションの記述、イニシャライザーの記述、ヘルパーモジュールの作成、DB のマイグレーション(修正)、埋め込み Ruby(ERB)との連携など、実際に動作するアプリケーションを構築する必要があるのです。

それは非常に楽しいものであり、プラグイン作成(Rails 側の話です。Ember については個人的にはあまり触れていませんが、Rails 側は大好きです)に慣れるための「最短ルート」でもあります!

さらに、Rails コンソールの使い方を学ぶ必要があります!Rails コンソールは本当に楽しく、私は毎日喜んで使っています。

今日、私の最もお気に入りのクライアントと AnyDesk で作業していました。彼が「在庫の新しいビューにできませんか?」と尋ねてきました。彼は私がそれをどうやって実現するかを見たいと言っていたのです。動作するようになった後、通話の終わりに彼が言いました。「これなら、数十年前なら数週間かかっていたことが、Rails なら 30 分でできてしまうなんて!」と。本当に素晴らしいことです、@leighno5 さん。ぜひ挑戦してください!

Rails を学べば、Discourse プラグインの作成は「すごい!」と驚くほど簡単だと気づくはずです。少なくとも Rails と Ruby の部分はそうです!

参考になれば幸いです。

「いいね!」 3

既存の #plugin コードを確認してください。現在、非常に多くのプラグインが存在するため、参考となる例が豊富にあります。過去の事例を読み飛ばさず、それを活用してください。

どうやら、1 つのメソッドをオーバーライドしたいだけのようです。これは plugin.rb でそのメソッドを再定義するだけで済みます(ベストプラクティスとしては、モジュールごとに別ファイルに分割するのが望ましいですが、1 つのメソッドの場合はそこまでする必要はありません!)。

「いいね!」 5

さらに無知をさらけ出し、すでに示していただいた親切につけ込むことになるかもしれませんが、もう少し詳しく説明していただけないでしょうか?あるいは、誰かがモジュールを上書きした別の例をご存知であれば、そのリンクを共有していただければ幸いです。「RTFM(マニュアルを読め)」という意見には全く反対ではありませんが、Discourse の仕組みに対する理解不足に悩まされています。さまざまなチュートリアルやドキュメントを時間をかけて読み直しているにもかかわらずです。はい、こうした基本的な質問をする私に対して、努力が足りないように見えることは承知しています。しかし、それは全く事実ではありません!

「いいね!」 3

PostGuardian でメソッドを定義した例はこちらです:

UserGuardian でも同様のことが可能です。既存のメソッド名を使用すれば、それがオーバーライドされます。

シンプルな解決策(堅牢性は低いが動作させる場合):

元のメソッドのコードをそのまま書き出し、必要に応じて編集するだけです。ただし、Discourse のコードが変更された場合、プラグインがインスタンスを壊す可能性があります。

高度な解決策(より堅牢なアプローチ):

super を使用して元のメソッドを継承することで、さらに優れた実装が可能になるかもしれません。詳しくはここでは説明しませんが、必ずしも動作する保証はありません。しかし、Discourse 側でそのメソッドが更新された際に、プラグインを修正しなくても自動的に反映されるため、ベストプラクティスです。

Discourse はプラットフォームであり、習熟には時間がかかります。一歩一歩進めていきましょう。

「いいね!」 6

まさに私が心配していたことです。次の段落で言及されている高度な方法は、ハウツーガイドに含まれていますか?既存のプラグインで使用(コピー)されている良いシンプルな例はありますか?新しいプラグインを作成する際に参考にできるものがあれば教えてください。

今は高度な方法は気にせず、まずは動作するようにしましょう。Ruby on Rails 全般については、他のオンラインガイドで調べてください。Discourse 自体やこのフォーラムの範囲外になる部分もあります。その点だけご承知おきください。

「いいね!」 1

お疲れ様でした!もし私がショートプラグインを書くところまでたどり着けたら、コアコードのアップグレードごとに確認し、関連するコアコードが変更されていればプラグインを書き直す必要があると理解しました。これで合っていますか?ありがとうございます。

「いいね!」 1

その通りです。定期的に確認し、特に不具合が発生し始めたら注意してください。Guardian コードはサイト認証のコーディングに関わるため、より重要なので、よく監視してください。

別の解決策として、テストケース(別名:specs)を追加し、それらを実行する自動化ジョブを設定する方法もあります。ただし、これはかなり複雑になります!

「いいね!」 2

さらに、追加課題として travis-ci.org を設定し、プラグインのテストを実行できるようにしておくと、問題が発生した際にいち早く通知を受け取ることができます。

「いいね!」 5

明らかに軽視すべき課題ではありません。ログイン画面と新規アカウント作成モーダルの変更、そしてTwitterの画像の削除を検討しています。後者のほうが最初のプロジェクトとして適しているかもしれません。よろしくお願いいたします。

もしこの投稿を見て、私と同じように行き詰まっていた方がいれば、実際に動作するようになった私のコードを以下に共有します。ファイルの修正は行わず、新しいファイル plugin.rb を作成し、以下の内容を記述しただけです。

# name: noms
# 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_usernamecan_edit_name の 2 つのメソッドを編集し、いくつかの戻り値を false から true に変更することだけでした。これで必要な動作を実現できました。

もちろん、さらに改善の余地はありますし、ここや他の場所でリンクされた投稿を読むことでベストプラクティスを学べたかもしれません。しかし、Ruby が全くの初心者で、コアの簡単な調整だけを実現したいという方には、必要なことがわかる最小限の動作例としてご参考ください。

このスレッドで私に根気強く向き合い、励ましやサポートをしてくれた皆さんに心から感謝しています。特に、以前も別の投稿で助けてくださった @merefield さんには大変お世話になりました。

「いいね!」 10

LOL

Discourseの全コードをフォークし、メインブランチを放棄するという当初の考えから、このような単純なタスクのためにここまで進歩しましたね。

お疲れ様でした :slight_smile:

「いいね!」 4

Install Discourse on Ubuntu or Debian for Development の手順をすべて踏んだのですか?それとも、本番サイトで試行錯誤しながら進めたのですか?