Ich habe beschlossen, das Plugin zu erstellen. Die Formularkomponente selbst wird korrekt über api.renderInOutlet gerendert. Die Daten werden jedoch nicht im Backend in der benutzerdefinierten Tabelle gespeichert.
Frontend-Setup:
Ich verwende api.renderInOutlet("composer-fields", MyOutletConnectorComponent), um eine GJS-Komponente (MyOutletConnectorComponent) zu rendern, wenn ein neues Thema in einer bestimmten Kategorie erstellt wird.
Diese MyOutletConnectorComponent rendert dann meine Haupt-GJS-Formular-Komponente (MyMarketFormComponenent).
Innerhalb von MyMarketFormComponenent aktualisiert die Benutzereingabe ein JavaScript-Objekt, das dann als Top-Level-Eigenschaft auf dem composerModel gesetzt wird, das von den Outlet-Argumenten bereitgestellt wird. Zum Beispiel:
// Innerhalb der MyMarketFormComponenent-Aktion
const currentData = this.args.composerModel.get("market_listing_data") || {};
const updatedData = { ...currentData, [fieldKey]: newValue };
this.args.composerModel.set("market_listing_data", updatedData);
In meinem Plugin-Initialisierer (tecenc-market-composer.js) verwende ich api.serializeOnCreate("market_listing_data", "market_listing_data");, um zu versuchen, diese Daten an das Backend zu übergeben. Ich verwende auch api.serializeToDraft("market_listing_data", "market_listing_data");.
Backend-Problem:
In meinem plugin.rb innerhalb des DiscourseEvent.on(:topic_created) do |topic, opts, user| ... end Handlers:
Ich prüfe, ob das Thema zur richtigen Kategorie gehört (das funktioniert).
Ich versuche dann, auf die serialisierten Daten zuzugreifen, indem ich market_data = opts[:market_listing_data] (oder opts["market_listing_data"]) verwende.
Das Problem ist, dass opts[:market_listing_data] durchweg nil ist.
Das Protokollieren von opts.keys bestätigt, dass mein Schlüssel market_listing_data nicht auf der obersten Ebene des opts-Hashs vorhanden ist. Der opts-Hash selbst enthält Standard-Schlüssel wie :raw, :title, :category, :archetype usw.
Mein plugin.rb-Snippet für das Ereignis:
# plugin.rb
# ...
module ::TecencMarket
SERIALIZED_DATA_KEY = "market_listing_data".freeze
end
# ...
after_initialize do
# ...
DiscourseEvent.on(:topic_created) do |topic, opts, user|
# ... (Logik zur Kategorienprüfung) ...
# Hier ist 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)
# ... Daten verarbeiten und in benutzerdefinierter Tabelle speichern ...
else
Rails.logger.warn "[MyPlugin] Market data not found in opts as expected."
end
end
# ...
end
Frage:
Was ist der richtige und zuverlässigste Weg, um sicherzustellen, dass ein JavaScript-Objekt, das als Top-Level-Eigenschaft auf dem composerModel gesetzt wird (z. B. composerModel.set("my_plugin_data_key", { ... });) mithilfe von GJS-Komponenten, korrekt von api.serializeOnCreate serialisiert und im opts-Hash des :topic_created-Ereignisses im Backend verfügbar gemacht wird?
Ist api.serializeOnCreate("my_key", "my_key") für beliebige Top-Level-Schlüssel auf dem composerModel aus einem GJS-Kontext erwartet, oder ist die Serialisierung über custom_fields (z. B. das Setzen von composerModel.custom_fields.my_plugin_key = {...} und die Verwendung von api.serializeOnCreate("custom_fields.my_plugin_key")) der einzige robuste/empfohlene Ansatz für diese Art der Datenübertragung für neue Themen?
Gibt es spezielle Überlegungen oder häufige Fallstricke bei der Verwendung von api.serializeOnCreate mit von GJS-Komponenten verwalteten Daten, die dazu führen könnten, dass die Daten nicht im opts-Hash enthalten sind?
Ich habe bestätigt, dass das Frontend-Formular Daten korrekt sammelt und sie auf der Eigenschaft composerModel.market_listing_data setzt. Das Problem scheint rein darin zu liegen, diese Daten zu serialisieren und an das Backend-Ereignis zu übergeben.
Jede Anleitung oder Beispiele für das empfohlene Muster hierfür im modernen Discourse wären sehr willkommen!
Zurückverfolgung meines vorherigen Problems, dass Daten nicht im opts-Hash ankommen, habe ich meine Strategie geändert und verwende nun den empfohlenen Weg über custom_fields, um Daten aus dem Composer-Formular meines Plugins zu serialisieren.
Aktueller Ansatz:
Frontend-Initializer:
Ich versuche sicherzustellen, dass composerModel.custom_fields und composerModel.custom_fields["tecenc_market_data"] (mein Daten-Schlüssel im Plugin) als Objekte initialisiert sind. Mein letzter Versuch beinhaltet die Verwendung von api.modifyClass("model:composer", ...), um die Initialisierungslogik zu init() und clearState() hinzuzufügen:
Ich verwende dann api.serializeOnCreate('custom_fields.tecenc_market_data'); und api.serializeToDraft('custom_fields.tecenc_market_data');.
Mein GJS-Formular-Komponent aktualisiert composerModel.custom_fields.tecenc_market_data.my_field = wert; (indem es ein neues custom_fields-Objekt für die Reaktivität setzt).
Backend plugin.rb:
Topic.register_custom_field_type("tecenc_market_data", :json) wird aufgerufen.
Der Event-Handler topic_created liest Daten aus topic.custom_fields["tecenc_market_data"].
Neuer kritischer Fehler:
Trotz dieser Versuche, custom_fields im composerModel zu initialisieren, erhalte ich nun konstant den folgenden JavaScript-Fehler, wenn ich den Composer für ein neues Thema öffne (durch Klicken auf den Button „Thema erstellen“):
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
Diese Fehleranzeige deutet darauf hin, dass this.model.custom_fields (im composerModel) undefined oder null ist, wenn der Kerncode von Discourse bei composer.js:1010 (innerhalb der open-Methode, die von openNewTopic aufgerufen wird) versucht, eine verschachtelte Eigenschaft zu setzen. Dies geschieht bevor mein Plugin-Formular überhaupt gerendert werden kann.
Fragen:
Angesichts dessen, dass das Kernmodell Composercustom_fields: {} initialisieren sollte, warum könnte composerModel.custom_fields zum Zeitpunkt composer.js:1010 während der openNewTopic-Sequenz in dieser Discourse-Version trotzdem undefined sein?
Ich speichere die Daten in einer benutzerdefinierten Datenbanktabelle.
addToSerializer dient dazu, Daten vom Server zum Client zu verschieben, nicht wahr?
Mein Problem ist, Daten vom Client zum Server zu verschieben, damit ich sie speichern kann. Deshalb verwende ich serializeOnCreate. Aber das Problem ist, dass die Daten nicht im opts-Hash ankommen. Die Antwort lautet also derzeit: Nein, die benutzerdefinierten Daten gelangen nicht wie erwartet in den opts-Hash. Sie gelangen nicht nach Rails.
Ich habe mir dieses Schulungsplugin angesehen, konnte es aber nicht für 6 benutzerdefinierte Felder zum Laufen bringen.