I dati personalizzati dal modulo GJS composer non sono in `opts` per l'evento `:topic_created`

Questo è in continuazione a questo: Custom topic fields per category or custom topic entry form per category?

Ho deciso di creare il plugin. Il componente del modulo stesso viene renderizzato correttamente tramite api.renderInOutlet. Tuttavia, i dati non vengono salvati sul backend nella tabella personalizzata.

Configurazione Frontend:

  1. Sto usando api.renderInOutlet("composer-fields", MyOutletConnectorComponent) per renderizzare un componente GJS (MyOutletConnectorComponent) quando viene creato un nuovo argomento in una categoria designata.

  2. Questo MyOutletConnectorComponent renderizza quindi il mio componente modulo principale GJS (MyMarketFormComponenent).

  3. All’interno di MyMarketFormComponenent, l’input dell’utente aggiorna un oggetto JavaScript che viene quindi impostato come proprietà di livello superiore sul composerModel fornito dagli argomenti dell’outlet. Ad esempio:

    // All'interno dell'azione MyMarketFormComponenent
    const currentData = this.args.composerModel.get("market_listing_data") || {};
    const updatedData = { ...currentData, [fieldKey]: newValue };
    this.args.composerModel.set("market_listing_data", updatedData);
    
  4. Nel mio inizializzatore del plugin (tecenc-market-composer.js), sto usando api.serializeOnCreate("market_listing_data", "market_listing_data"); per tentare di passare questi dati al backend. Uso anche api.serializeToDraft("market_listing_data", "market_listing_data");.

Problema Backend:

Nel mio plugin.rb, all’interno dell’handler DiscourseEvent.on(:topic_created) do |topic, opts, user| ... end:

  • Verifico se l’argomento è nella categoria corretta (questo funziona).
  • Quindi provo ad accedere ai dati serializzati usando market_data = opts[:market_listing_data] (o opts["market_listing_data"]).
  • Il problema è che opts[:market_listing_data] è costantemente nil.
  • Il logging di opts.keys conferma che la mia chiave market_listing_data non è presente al livello superiore dell’hash opts. L’hash opts stesso contiene chiavi standard come :raw, :title, :category, :archetype, ecc.

Il mio snippet plugin.rb per l’evento:

# plugin.rb
# ...
module ::TecencMarket
  SERIALIZED_DATA_KEY = "market_listing_data".freeze
end
# ...
after_initialize do
  # ...
  DiscourseEvent.on(:topic_created) do |topic, opts, user|
    # ... (logica di controllo della categoria) ...

    # È qui che 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)
      # ... elabora e salva i dati nella tabella personalizzata ...
    else
      Rails.logger.warn "[MyPlugin] Market data not found in opts as expected."
    end
  end
  # ...
end

Domanda:

  1. Qual è il modo corretto e più affidabile per garantire che un oggetto JavaScript impostato come proprietà di livello superiore sul composerModel (ad esempio, composerModel.set("my_plugin_data_key", { ... });) utilizzando componenti GJS venga correttamente serializzato da api.serializeOnCreate e reso disponibile nell’hash opts dell’evento :topic_created sul backend?

  2. api.serializeOnCreate("my_key", "my_key") è previsto che funzioni per chiavi arbitrarie di livello superiore impostate sul composerModel da un contesto GJS, o la serializzazione tramite custom_fields (ad esempio, impostando composerModel.custom_fields.my_plugin_key = {...} e utilizzando api.serializeOnCreate("custom_fields.my_plugin_key")) è l’unico approccio robusto/raccomandato per questo tipo di trasferimento dati per nuovi argomenti?

  3. Ci sono considerazioni specifiche o errori comuni quando si utilizza api.serializeOnCreate con dati gestiti da componenti GJS che potrebbero causare la mancata inclusione dei dati nell’hash opts?

Ho confermato che il modulo frontend sta raccogliendo correttamente i dati e li sta impostando sulla proprietà composerModel.market_listing_data. Il problema sembra essere puramente nell’ottenere questi dati serializzati e passati all’evento backend.

Qualsiasi guida o esempio del modello raccomandato per questo nel moderno Discourse sarebbe molto apprezzato!

Grazie!

Ciao di nuovo,

In seguito al mio problema precedente riguardo al fatto che i dati non raggiungessero l’hash opts, ho modificato la mia strategia per utilizzare il percorso raccomandato custom_fields per serializzare i dati dal modulo del plugin del mio compositore.

Approccio Attuale:

  1. Inizializzatore Frontend:
    • Sto cercando di assicurarmi che composerModel.custom_fields e composerModel.custom_fields["tecenc_market_data"] (la chiave dei dati del mio plugin) siano inizializzati come oggetti. La mia ultima prova consiste nell’usare api.modifyClass("model:composer", ...) per aggiungere la logica di inizializzazione a init() e clearState():

      // Nel mio inizializzatore plugin (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);
          }
        }
      });
      
    • Successivamente utilizzo api.serializeOnCreate('custom_fields.tecenc_market_data'); e api.serializeToDraft('custom_fields.tecenc_market_data');.

    • Il mio componente GJS del modulo aggiorna composerModel.custom_fields.tecenc_market_data.my_field = value; (impostando un nuovo oggetto custom_fields per la reattività).

  2. Backend plugin.rb:
    • Viene chiamato Topic.register_custom_field_type("tecenc_market_data", :json).
    • L’handler di evento topic_created si aspetta di leggere i dati da topic.custom_fields["tecenc_market_data"].

Nuovo Errore Blocante:

Nonostante questi tentativi di inizializzare custom_fields sul composerModel, sto ora incontrando sistematicamente il seguente errore JavaScript quando provo ad aprire il composer per un nuovo argomento (cliccando sul pulsante “Create Topic”):


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

Questo errore indica che this.model.custom_fields (sul composerModel) è undefined o null quando il codice core di Discourse in composer.js:1010 (all’interno del metodo open, chiamato da openNewTopic) tenta di impostare una proprietà nidificata su di esso. Questo accade prima che il modulo del mio plugin possa essere nemmeno renderizzato.

Domande:

  1. Dato che il modello Composer core dovrebbe inizializzare custom_fields: {}, perché composerModel.custom_fields potrebbe comunque essere undefined a composer.js:1010 durante la sequenza openNewTopic in questa versione di Discourse?
  2. L’approccio api.modifyClass("model:composer", ...) in un initializer è il modo corretto/più efficace per garantire che custom_fields (e le chiavi nested del plugin al suo interno) siano inizializzati come oggetti abbastanza presto da prevenire questo errore core? Se no, qual è il pattern raccomandato?
  3. Potrebbe esserci un problema di timing in cui i passaggi di inizializzazione del composer core vengono eseguiti e si aspettano che custom_fields sia disponibile prima che gli initializer del plugin, usando api.modifyClass, abbiano effettivamente effetto sulla prototipo o sulle istanze del modello Composer?

Qualsiasi insight su questo errore “Property set failed” nel core del composer e sulle migliori pratiche per i plugin per interagire in modo sicuro con composerModel.custom_fields durante l’inizializzazione sarebbe estremamente utile.

Grazie per il vostro tempo!

Penso che tu debba aggiungere i tuoi dati al serializer lato Rails.

I tuoi dati arrivano in Rails? Dove li stai memorizzando?

Guarda i plugin che hanno addToSerializer.

Sto salvando i dati in una tabella di database personalizzata.

addToSerializer serve per spostare i dati dal server al client, vero?

Il mio problema è spostare i dati dal client al server in modo da poterli salvare. Quindi sto usando serializeOnCreate. Ma il problema è che i dati non fluiscono nell’hash opts. Quindi, attualmente, la risposta è no, i dati personalizzati non stanno entrando nell’hash opts come previsto. Non stanno arrivando a Rails.

Ho esaminato questo plugin educativo ma non sono riuscito a farlo funzionare per 6 campi personalizzati.

1 Mi Piace

Funzionato.

Mi mancava questo passaggio: api.serializeToTopic(MY_BLOB_KEY, \topic.${MY_BLOB_KEY}\);

2 Mi Piace