GJSコンポーザフォームからのカスタムデータが `:topic_created` イベントの `opts` に含まれていません

これはこれの続きです- Custom topic fields per category or custom topic entry form per category?

プラグインを作成することにしました。フォームコンポーネント自体は api.renderInOutlet を介して正しくレンダリングされています。しかし、データがバックエンドのカスタムテーブルに保存されていません。

フロントエンドのセットアップ:

  1. 指定されたカテゴリで新しいトピックが作成されるときに、GJSコンポーネント(MyOutletConnectorComponent)をレンダリングするために api.renderInOutlet("composer-fields", MyOutletConnectorComponent) を使用しています。

  2. この MyOutletConnectorComponent は、メインのGJSフォームコンポーネント(MyMarketFormComponenent)をレンダリングします。

  3. MyMarketFormComponenent 内で、ユーザー入力はJavaScriptオブジェクトを更新し、それがアウトレット引数によって提供される composerModel のトップレベルプロパティとして設定されます。例:

    // MyMarketFormComponenent アクション内
    const currentData = this.args.composerModel.get("market_listing_data") || {};
    const updatedData = { ...currentData, [fieldKey]: newValue };
    this.args.composerModel.set("market_listing_data", updatedData);
    
  4. プラグイン初期化子(tecenc-market-composer.js)で、このデータをバックエンドに渡そうとして api.serializeOnCreate("market_listing_data", "market_listing_data"); を使用しています。また、api.serializeToDraft("market_listing_data", "market_listing_data"); も使用しています。

バックエンドの問題:

plugin.rbDiscourseEvent.on(:topic_created) do |topic, opts, user| ... end ハンドラ内:

  • トピックが正しいカテゴリにあるかを確認します(これは機能します)。
  • 次に、market_data = opts[:market_listing_data](または opts[\"market_listing_data\"])を使用してシリアル化されたデータにアクセスしようとします。
  • 問題は、opts[:market_listing_data] が一貫して nil であることです。
  • opts.keys をログに記録すると、market_listing_data キーが opts ハッシュのトップレベルに存在しないことが確認されます。opts ハッシュ自体には、:raw:title:category:archetypeなどの標準キーが含まれています。

plugin.rb のイベント用スニペット:

# plugin.rb
# ...
module ::TecencMarket
  SERIALIZED_DATA_KEY = "market_listing_data".freeze
end
# ...
after_initialize do
  # ...
  DiscourseEvent.on(:topic_created) do |topic, opts, user|
    # ... (カテゴリチェックロジック) ...

    # ここで market_data が nil になります
    market_data = opts[TecencMarket::SERIALIZED_DATA_KEY.to_sym]

    Rails.logger.info "[MyPlugin] Opts keys: #{opts.keys.inspect}"
    Rails.logger.info "[MyPlugin] market_data from opts: #{market_data.inspect}"

    if market_data.present? && market_data.is_a?(Hash)
      # ... データを処理してカスタムテーブルに保存 ...
    else
      Rails.logger.warn "[MyPlugin] Market data not found in opts as expected."
    end
  end
  # ...
end

質問:

  1. GJSコンポーネントから composerModel にトップレベルプロパティとして設定されたJavaScriptオブジェクト(例:composerModel.set("my_plugin_data_key", { ... });)が、api.serializeOnCreate によって正しくシリアル化され、バックエンドの :topic_created イベントの opts ハッシュで利用可能であることを保証する、最も信頼性の高い方法は何ですか?

  2. api.serializeOnCreate("my_key", "my_key") は、GJSコンポーネントによって管理されるデータに対して、composerModel に設定された任意のトップレベルキーに対して機能することが期待されていますか?それとも、custom_fields を介したシリアル化(例:composerModel.custom_fields.my_plugin_key = {...} を設定し、api.serializeOnCreate("custom_fields.my_plugin_key") を使用する)が、新しいトピックのこの種のデータ転送のための唯一の堅牢/推奨されるアプローチですか?

  3. GJSコンポーネントによって管理されるデータで api.serializeOnCreate を使用する際に、データが opts ハッシュに含まれない原因となる可能性のある、特別な考慮事項や一般的な落とし穴はありますか?

フロントエンドフォームがデータを正しく収集し、composerModel.market_listing_data プロパティに設定していることを確認しました。問題は、このデータをシリアル化してバックエンドイベントに渡すことにあるようです。

最新のDiscourseでの推奨パターンに関するガイダンスや例があれば、大いに感謝します!

ありがとうございます!

こんにちは、

私の前回の問題に続き、データが opts ハッシュに到達しない件について、私はプラグインのコンポーザーフォームからデータをシリアル化するために推奨されている custom_fields 経路を使用する戦略に切り替えました。

現在のアプローチ:

  1. フロントエンドのイニシャライザ:
    • composerModel.custom_fieldscomposerModel.custom_fields["tecenc_market_data"](私のプラグインのデータキー)がオブジェクトとして初期化されていることを確認しようとしています。最新の試みとして、api.modifyClass("model:composer", ...) を使用して init()clearState() に初期化ロジックを追加しています:

      // プラグインのイニシャライザ (tecenc-market-composer.js) にて
      api.modifyClass("model:composer", {
        pluginId: "tecencMarketInitCustomFieldsOnComposer",
        init() {
          this._super(...arguments); 
          if (!this.custom_fields || typeof this.custom_fields !== 'object') {
            this.custom_fields = {};
          }
          if (!this.custom_fields["tecenc_market_data"] || typeof this.custom_fields["tecenc_market_data"] !== 'object') {
            this.custom_fields["tecenc_market_data"] = {};
          }
        },
        clearState() {
          this._super(...arguments); 
          if (!this.custom_fields || typeof this.custom_fields !== 'object') {
            this.set("custom_fields", {});
          }
          let cf = this.get("custom_fields"); 
          if (!cf["tecenc_market_data"] || typeof cf["tecenc_market_data"] !== 'object') {
            const newCustomFields = { ...cf }; 
            newCustomFields["tecenc_market_data"] = {};
            this.set("custom_fields", newCustomFields);
          }
        }
      });
      
    • その後、api.serializeOnCreate('custom_fields.tecenc_market_data');api.serializeToDraft('custom_fields.tecenc_market_data'); を使用しています。

    • 私のGJSフォームコンポーネントは composerModel.custom_fields.tecenc_market_data.my_field = value; を更新しています(反応性のために新しい custom_fields オブジェクトを設定)。

  2. バックエンドの plugin.rb:
    • Topic.register_custom_field_type("tecenc_market_data", :json) が呼び出されています。
    • topic.custom_fields["tecenc_market_data"] からデータを読み取る topic_created イベントハンドラがあります。

新たなエラー:

これらの custom_fieldscomposerModel で初期化しようとしたにも関わらず、トピックの新規作成時(「トピック作成」ボタンをクリックしてコンポーザーを開くとき)に次のJavaScriptエラーが一貫して発生しています:


Uncaught (in promise) Error: Property set failed: object in path "custom_fields" could not be found.

Ember 3

open composer.js:1010

open composer.js:1009

_setModel composer.js:1451

open composer.js:1401

openNewTopic composer.js:1410

createTopic list.js:167

clickCreateTopicButton d-navigation.gjs:224

_triggerAction d-button.gjs:138

Ember 11

_triggerAction d-button.gjs:135

click d-button.gjs:93

source chunk.8d6366d70b85d1b69fdc.d41d8cd9.js:94366

Ember 2

source chunk.8d6366d70b85d1b69fdc.d41d8cd9.js:94040

Ember 26 property_set-BapAkp3X.js:79:10

このエラーは、composerModelthis.model.custom_fieldsundefinedまたはnullであることを示しています。これは、composer.js:1010でコアのDiscourseコードが(openメソッドの中で、openNewTopicによって呼び出される)ネストされたプロパティを設定しようとしたときに起こります。この処理は、私のプラグインのフォームがまだレンダリングされる前に行われます。

質問:

  1. コアのComposerモデルはcustom_fields: {}を初期化すべきなのに、なぜcomposer.js:1010openNewTopicのシーケンス中にcomposerModel.custom_fieldsが未定義のままでしょうか、このDiscourseのバージョンでは?
  2. 初期化子で`api.modifyClass(

あなたは、Rails側でシリアライザにデータを追加する必要があると思います。

データはRailsに到達していますか?どこに保存していますか?

addToSerializerを持つプラグインを確認してください。

カスタムデータベーステーブルにデータを保存しています。

addToSerializer はサーバーからクライアントへデータを移動するためのもので、そうですよね?

私の問題は、データを保存するためにクライアントからサーバーへデータを移動することです。そのため、serializeOnCreate を使用していますが、データが opts ハッシュに流れてこないという問題があります。そのため、現在のところ、答えは いいえ、カスタムデータは期待どおりに opts ハッシュに入っていません。Rails に到達していません。 です。

この教育用プラグインを調べましたが、6つのカスタムフィールドで機能させることができませんでした。

「いいね!」 1

動作させることができました。

このステップを見落としていました:api.serializeToTopic(MY_BLOB_KEY, \topic.${MY_BLOB_KEY}\);

「いいね!」 2