Filtri personalizzati degli argomenti: i parametri URL non raggiungono `TopicQuery.options`

Mentre costruisco un plugin con filtri personalizzati per la lista di argomenti (ad esempio, per prezzo, posizione) usando i parametri di query URL. L’URL si aggiorna correttamente (ad esempio, ...?market_item_statuses=Available), ma i parametri non appaiono in topic_query.options sul server.

Configurazione:

  1. Registrazione dei Parametri lato Client (tecenc-discovery-params.js):

    // tecenc-discovery-params.js
    import { apiInitializer } from "discourse/lib/api";
    
    export default apiInitializer("1.37.3", (api) => {
      const MARKET_PARAMS_KEYS = [
        "market_price_min", "market_price_max", "market_location",
        "market_conditions", "market_warranty", "market_item_statuses"
      ];
      MARKET_PARAMS_KEYS.forEach(paramKey => {
        api.addDiscoveryQueryParam(paramKey, { replace: true, refreshModel: true });
      });
    });
    
  2. Tentativo di whitelisting lato Server (plugin.rb):

    # plugin.rb
    module ::Tecenc
      MARKET_PARAMS_KEYS = [
        :market_price_min, :market_price_max, :market_location,
        :market_conditions, :market_warranty, :market_item_statuses
      ].freeze
    end
    
    # after_initialize do
      if SiteSetting.tecenc_enabled?
        if defined?(::TopicQuery.add_custom_param_handler)
          ::Tecenc::MARKET_PARAMS_KEYS.each do |param_key|
            ::TopicQuery.add_custom_param_handler(param_key) { |value| value } # Semplificato per brevità
          end
          Rails.logger.info "[Tecenc] Registrato con add_custom_param_handler."
        elsif defined?(::TopicQuery) && ::TopicQuery.methods.include?(:extra_options_whitelist)
          current_whitelist = ::TopicQuery.extra_options_whitelist || []
          new_whitelist = (current_whitelist + ::Tecenc::MARKET_PARAMS_KEYS).uniq
          ::TopicQuery.extra_options_whitelist(*new_whitelist)
          Rails.logger.info "[Tecenc] Esteso extra_options_whitelist."
        else
          Rails.logger.warn "[Tecenc] PLUGIN_WARN: Impossibile trovare il metodo per whitelisting i parametri di TopicQuery."
        end
      end
    
  3. Logica di Filtering lato Server (plugin.rb) (after_initialize / if enabled):

    # plugin.rb (all'interno di after_initialize / se abilitato)
    ::TopicQuery.add_custom_filter(:"tecenc_filters") do |topics, topic_query|
      opts = topic_query.options
      Rails.logger.info "[Tecenc_TopicQuery] Opzioni: #{opts.inspect}" # LOG CRITICO
    
      # market_params_present = ::Tecenc::MARKET_PARAMS_KEYS.any? { |p| opts[p].present? }
      # if market_params_present
      #   # ... logica di filtraggio usando opts[key] ...
      # end
      topics # o topics modificati
    end
    

Il Problema (Log):

  1. La whitelist dei parametri fallisce:

    [Tecenc] PLUGIN_WARN: Impossibile trovare un metodo adatto (add_custom_param_handler o extra_options_whitelist) per whitelisting dei parametri personalizzati per TopicQuery.
    
  2. opts in TopicQuery.add_custom_filter manca dei nostri parametri personalizzati:
    Quando l’URL è ...?market_item_statuses=Available, il log mostra:

    [Tecenc_TopicQuery] Opzioni: {:category=>5, :filter=>"default", :topic_ids=>nil, :category_id=>5}
    

I nostri market_item_statuses (e altri parametri personalizzati) non sono presenti.

Il nostro ambiente:

Domande:

  1. Qual è la migliore pratica attuale per garantire che i parametri personalizzati dell’URL raggiungano topic_query.options nelle versioni recenti di Discourse?
  2. Perché i nostri tentativi di usare add_custom_param_handler o extra_options_whitelist falliscono con l’avviso “Could not find a suitable method”?
  3. Esiste un metodo alternativo per la registrazione dei parametri con TopicQuery che dovremmo usare?

Ogni aiuto sarebbe molto apprezzato!

Ho appena notato che add_custom_param_handler non è nemmeno disponibile come metodo su TopicQuery. Esiste un altro modo per creare filtri personalizzati per gli argomenti nelle versioni più recenti di Discourse?

Metodi singleton di TopicQuery: [:add_custom_filter, :apply_custom_filters, :new_filter, :public_valid_options, :remove_custom_filter, :remove_muted_tags, :results_filter_callbacks, :results_filter_callbacks=, :tracked_filter, :unread_filter, :valid_options, :validate?, :validators, :yaml_tag]

Rapporto di avanzamento finora:

  1. Ho confermato che i metodi di whitelist statica TopicQuery come add_custom_param_handler o extra_options_whitelist non sono disponibili come metodi di classe nella mia versione di Discourse, quindi questi approcci sono stati abbandonati.

  2. Ho implementato una patch per ListController#build_topic_list_options per iniettare i miei parametri URL personalizzati (ad esempio, market_item_statuses, market_price_min) nel dizionario opts prima che venga chiamato TopicQuery.new.

  3. Questa parte ora funziona! Quando effettuo una richiesta come /c/market/5/l/latest.json?filter=defaultmarket_item_statuses=Available, i miei log del server confermano l’iniezione:

    [TecencMarket_ListControllerExt_BuildOptsV3] Iniettato in opts: market_item_statuses = Available
    
    

    Quindi, TopicQuery.new(user, opts) ora riceve opts che contiene i miei parametri personalizzati.

Punto attuale di blocco: errore 500  blocco del filtro non raggiunto

Nonostante i parametri siano ora correttamente passati all’inizializzatore di TopicQuery, ottengo ancora un errore interno del server 500 quando la richiesta include questi parametri di mercato personalizzati.

Per isolare il problema, ho semplificato il mio blocco TopicQuery.add_custom_filter(:"tecenc_market_filters") al minimo assoluto.

# plugin.rb - Blocca filtro personalizzato semplificato attuale
if ::TopicQuery.respond_to?(:add_custom_filter)
  ::TopicQuery.add_custom_filter(:"tecenc_market_filters") do |topics, topic_query|
    topics_originali = topics
    opts = topic_query.options
    log_prefix_query = "[TecencMarket_SimplifiedFilter_V1.1_Test]" # Prefisso di debug

    Rails.logger.info "#{log_prefix_query} Opts ricevuti da TopicQuery: #{opts.inspect}"

    if opts[:market_item_statuses].present?
      Rails.logger.info "#{log_prefix_query} 'market_item_statuses' È PRESENTE in opts: #{opts[:market_item_statuses]}"
    else
      Rails.logger.info "#{log_prefix_query} 'market_item_statuses' NON È PRESENTE in opts."
    end
    
    Rails.logger.info "#{log_prefix_query} Restituisco la relazione degli argomenti originali."
    topics_originali # ritorno implicito
  end
  Rails.logger.info "[TecencMarket] Applicato filtro personalizzato SEMPLIFICATO (V1.1_Test)."
end

Osservazioni con questo filtro semplificato:

  • Richieste senza il mio parametro di filtro personalizzato (es., /c/market/5/l/latest.json?filter=default):

    • Il blocco di filtro semplificato registra correttamente:

      [TecencMarket_SimplifiedFilter_V1.1_Test] Opts ricevuti da TopicQuery: {:category=>5, :filter=>"default", ...}
      [TecencMarket_SimplifiedFilter_V1.1_Test] 'market_item_statuses' NON È PRESENTE in opts.
      [TecencMarket_SimplifiedFilter_V1.1_Test] Restituisco la relazione degli argomenti originali.
      
      
    • La pagina si carica con un 200 OK.

  • Richieste con il mio parametro di filtro personalizzato (es., /c/market/5/l/latest.json?filter=defaultmarket_item_statuses=Available):

    • L’output di log del ListController appare: [TecencMarket_ListControllerExt_BuildOptsV3] Injected into opts: market_item_statuses = Available

    • Si verifica un Completed 500 Internal Server Error in ...ms immediatamente dopo.

    • ** Fondamentalmente, NESSUN log proveniente dal blocco filtrante semplificato (senza le linee [TecencMarket_SimplifiedFilter_V1.1_Test]...) compare per questa richiesta fallita.**

Questo indica che l’errore 500 avviene dopo l’inizializzazione di TopicQuery con il hash opts (che ora contiene i miei parametri personalizzati), ma prima o proprio mentre il meccanismo centrale di Discourse TopicQuery#apply_custom_filters tenta di eseguire il mio blocco di filtro registrato (e ora estremamente semplice).

Ho difficoltà a isolare l’eccezione Ruby specifica e il backtrace completo da development.log che precede immediatamente la linea “Completed 500…” per le richieste fallite (gli estratti di log che ho raccolto mostrano solo la linea 500, ma non il messaggio di errore dettagliato appena prima).

Domanda di follow-up:

Considerando che:

  1. I parametri personalizzati vengono ora iniettati con successo in TopicQuery.options tramite la patch del ListController.

  2. Si verifica un errore 500 quando questi parametri personalizzati sono presenti in opts.

  3. Questo errore 500 avviene prima che il blocco di filtro personalizzato estremamente semplificato (che si limita a loggare e restituire la relazione originale) venga eseguito con la sua prima riga di codice per la richiesta con parametri personalizzati.

  4. È su Discourse 3.5.0.beta3-dev.

Cosa potrebbe causare che TopicQuery stesso, o il suo metodo apply_custom_filters, generino un errore prima di invocare un filtro personalizzato registrato, specificamente quando il hash options contiene queste chiavi specifiche del plugin? La precedente LocalJumpError che sospettavamo potrebbe ancora essere rilevante a un livello più basso nel modo in cui apply_custom_filters gestisce l’iterazione o la chiamata ai blocchi di filtro, anche se il mio blocco semplificato è solo un ritorno implicito?

Qualsiasi guida su cosa verificare successivamente nel comportamento di TopicQuery con questi tipi di opzioni personalizzate, o consigli su come ottenere in modo affidabile il backtrace completo per l’errore 500 in questa situazione, sarebbe estremamente utile.