これはこれの続きです- Custom topic fields per category or custom topic entry form per category?
プラグインを作成することにしました。フォームコンポーネント自体は api.renderInOutlet を介して正しくレンダリングされています。しかし、データがバックエンドのカスタムテーブルに保存されていません。
フロントエンドのセットアップ:
指定されたカテゴリで新しいトピックが作成されるときに、GJSコンポーネント(MyOutletConnectorComponent)をレンダリングするために api.renderInOutlet("composer-fields", MyOutletConnectorComponent) を使用しています。
この MyOutletConnectorComponent は、メインのGJSフォームコンポーネント(MyMarketFormComponenent)をレンダリングします。
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);
プラグイン初期化子(tecenc-market-composer.js)で、このデータをバックエンドに渡そうとして api.serializeOnCreate("market_listing_data", "market_listing_data"); を使用しています。また、api.serializeToDraft("market_listing_data", "market_listing_data"); も使用しています。
バックエンドの問題:
plugin.rb の DiscourseEvent.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
質問:
GJSコンポーネントから composerModel にトップレベルプロパティとして設定されたJavaScriptオブジェクト(例:composerModel.set("my_plugin_data_key", { ... });)が、api.serializeOnCreate によって正しくシリアル化され、バックエンドの :topic_created イベントの opts ハッシュで利用可能であることを保証する、最も信頼性の高い方法は何ですか?
api.serializeOnCreate("my_key", "my_key") は、GJSコンポーネントによって管理されるデータに対して、composerModel に設定された任意のトップレベルキーに対して機能することが期待されていますか?それとも、custom_fields を介したシリアル化(例:composerModel.custom_fields.my_plugin_key = {...} を設定し、api.serializeOnCreate("custom_fields.my_plugin_key") を使用する)が、新しいトピックのこの種のデータ転送のための唯一の堅牢/推奨されるアプローチですか?
GJSコンポーネントによって管理されるデータで api.serializeOnCreate を使用する際に、データが opts ハッシュに含まれない原因となる可能性のある、特別な考慮事項や一般的な落とし穴はありますか?
フロントエンドフォームがデータを正しく収集し、composerModel.market_listing_data プロパティに設定していることを確認しました。問題は、このデータをシリアル化してバックエンドイベントに渡すことにあるようです。
最新のDiscourseでの推奨パターンに関するガイダンスや例があれば、大いに感謝します!
ありがとうございます!
こんにちは、
私の前回の問題に続き、データが opts ハッシュに到達しない件について、私はプラグインのコンポーザーフォームからデータをシリアル化するために推奨されている custom_fields 経路を使用する戦略に切り替えました。
現在のアプローチ:
フロントエンドのイニシャライザ:
composerModel.custom_fields と composerModel.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 オブジェクトを設定)。
バックエンドの plugin.rb:
Topic.register_custom_field_type("tecenc_market_data", :json) が呼び出されています。
topic.custom_fields["tecenc_market_data"] からデータを読み取る topic_created イベントハンドラがあります。
新たなエラー:
これらの custom_fields を composerModel で初期化しようとしたにも関わらず、トピックの新規作成時(「トピック作成」ボタンをクリックしてコンポーザーを開くとき)に次の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
このエラーは、composerModelのthis.model.custom_fieldsがundefinedまたはnullであることを示しています。これは、composer.js:1010でコアのDiscourseコードが(openメソッドの中で、openNewTopicによって呼び出される)ネストされたプロパティを設定しようとしたときに起こります。この処理は、私のプラグインのフォームがまだレンダリングされる前に行われます。
質問:
コアのComposerモデルはcustom_fields: {}を初期化すべきなのに、なぜcomposer.js:1010のopenNewTopicのシーケンス中にcomposerModel.custom_fieldsが未定義のままでしょうか、このDiscourseのバージョンでは?
初期化子で`api.modifyClass(
pfaffman
(Jay Pfaffman)
2025 年 5 月 20 日午後 10:14
3
あなたは、Rails側でシリアライザにデータを追加する必要があると思います。
データはRailsに到達していますか?どこに保存していますか?
addToSerializerを持つプラグインを確認してください。
カスタムデータベーステーブルにデータを保存しています。
addToSerializer はサーバーからクライアントへデータを移動するためのもので、そうですよね?
私の問題は、データを保存するためにクライアントからサーバーへデータを移動することです。そのため、serializeOnCreate を使用していますが、データが opts ハッシュに流れてこないという問題があります。そのため、現在のところ、答えは いいえ、カスタムデータは期待どおりに opts ハッシュに入っていません。Rails に到達していません。 です。
この教育用プラグインを調べましたが、6つのカスタムフィールドで機能させることができませんでした。
Discourse plugin showing how to add custom fields to Discourse topics
「いいね!」 1
動作させることができました。
このステップを見落としていました:api.serializeToTopic(MY_BLOB_KEY, \topic.${MY_BLOB_KEY}\);
「いいね!」 2