Themen anhand eines benutzerdefinierten Feldes abrufen?

Mit dieser sehr hilfreichen Anleitung von @angus konnte ich benutzerdefinierte Felder zu Themen und Gruppen hinzufügen.

Gibt es nach dem erfolgreichen Hinzufügen eines benutzerdefinierten Feldes eine (effiziente) Möglichkeit, Elemente basierend auf diesem benutzerdefinierten Feld abzurufen?

Nehmen wir zum Beispiel an, ich füge das benutzerdefinierte Feld fun_level zu Themen hinzu. Dadurch wird nun das Feld topic.fun_level (ein String) über mein Plugin hinzugefügt.

Jetzt möchte ich eine Liste aller Themen abrufen und anzeigen, bei denen fun_level gleich „super-duper-fun

1 „Gefällt mir“

Ich glaube, ich habe eine Methode gefunden, um Themen basierend auf einem benutzerdefinierten Feld abzurufen: Suche danach und hole die Ergebnisse.

Hier ist ein Beispiel, wobei angenommen wird, dass Sie irgendwo einen Button mit der Aktion “searchForTopics()” haben und Themen mit dem benutzerdefinierten Feld fun_level gleich “super-duper-fun” erhalten möchten:

(dies würde in etwas JS ES6-Code gehen, wie z. B. einem Initialisierer):


import Topic from 'discourse/models/topic'; // basierend auf dem Code unten nicht erforderlich, aber wahrscheinlich relevant für andere verwandte Aktionen, die Sie durchführen möchten
import { ajax } from 'discourse/lib/ajax';

export default {
    actions: {
        checkTopic(){
            let custom_field_value = 'super-duper-fun'
            let searchTerm = 'fun_level:' + custom_field_value
            let args = { q: searchTerm }
            ajax("/search", { data: args }).then(results => {
                let topics = results.topics
                topics.forEach(topic => {
                   // nur um eine Liste der Themennamen zu erhalten
                    console.log('topic name = ')
                    console.log(topic)
                })
            })
        }
    }
}

Das funktioniert. Aber ist dies der effizienteste Weg, dies zu tun?

Zum Beispiel: Ist diese Methode, die die Suche verwendet, so effizient wie die Methode, die Discourse verwendet, um Ihnen Themen anzuzeigen, die einem bestimmten Tag entsprechen, wenn Sie zu dieser Tag-Seite gehen?

1 „Gefällt mir“

So geht’s:

  1. Auf dem Client: Fügen Sie einen Topic-Query-Parameter mit api.addDiscoveryQueryParam hinzu.

  2. Auf dem Server: Filtern Sie Topic-Abfragen nach dem Parameter mit add_custom_filter in der Klasse TopicQuery (siehe lib/topic_query).

Die Callback-Funktion für add_custom_filter sieht etwa so aus:

::TopicQuery.add_custom_filter(:field_name) do |topics, query|
  if query.options[:field_name]
    topics.where("topics.id in (
      SELECT topic_id FROM topic_custom_fields
      WHERE (name = 'field_name')
      AND value = '#{query.options[:field_name]}'
    )")
  else
    topics
  end
end
3 „Gefällt mir“

EDIT: Nach genauerer Betrachtung von api.addDiscoveryQueryParam verstehe ich nun die Grundidee:

Ich möchte programmatisch alle Themen mit dem benutzerdefinierten Feld fun_level = super-duper-fun abrufen. Vielleicht könnte eine Controller-Methode das übernehmen? (bin dabei noch am Klären).

Eine Alternative wäre eine Suche mit ajax("/search"), bei der ich alle Themen basierend auf dem benutzerdefinierten Feld fun_level=super-duper-fun durchsuche. Doch das bloße Erstellen des benutzerdefinierten Feldes reicht nicht aus, um dies zu ermöglichen. Ich muss das Feld fun_level als eines der Felder definieren, gegen die gesucht werden kann (genau wie bei bestimmten Kategorien, Tags usw.), und das geschieht nicht automatisch.

Auf irgendeine Weise sind api.addDiscoveryQueryParam in einer JS-Datei und TopicQuery in plugin.rb erforderlich, um dies zu erreichen. Aber ehrlich gesagt ist es mir noch nicht gelungen, es zum Laufen zu bringen. Ich habe einige Plugins gesehen, die diese Methoden verwenden, aber ich konnte nicht herausfinden, wie sie es „zum Abschluss bringen“. Ich vermute, dass zusätzlicher Code erforderlich ist, den ich bisher noch nicht gefunden habe.

Wie kommt man von diesen Methoden dazu, dass das benutzerdefinierte Feld tatsächlich als Suchbegriff verfügbar ist?

Frühere Antwort

Danke, @angus. Zur Klarstellung: Das Ziel ist nicht, dass Benutzer Suchwerte manuell im Suchfeld eingeben. Das Ziel ist es, programmatisch Themen basierend auf einem bestimmten benutzerdefinierten Feld abzurufen. Beispielsweise würde der Benutzer zur Seite /fun_levels/super-duper-fun gehen und alle Themen laden, bei denen das Feld fun_level = ‘super-duper-fun’ ist.

Ist api.addDiscoveryQueryParam für diesen Zweck?

Bei der Betrachtung von Beispielen wie hier bin ich mir nicht sicher, wie addDiscoveryQueryParam funktioniert, um tatsächlich die Themen abzurufen (ich glaube nicht, dass der Aufruf dieser Methode Ergebnisse zurückgibt, die ich parsen kann).

Vielleicht dient es dazu, Benutzern die manuelle Suche nach dem Begriff im Suchfeld zu ermöglichen? Das ist nicht die Situation, die ich anstrebe. (Es könnte sein, dass mir etwas entgangen ist).

Ich habe zuvor die Verwendung von ajax("/search...") erwähnt, da dies bisher die beste Lösung für mich war, um Themen zurückzugeben. Ich frage mich jedoch, ob es einen effizienteren Weg gibt, dies zu tun, einschließlich der Einrichtung eines Modells und einer Controller-Methode, um Themen automatisch anzuzeigen, ähnlich wie es bei tags/:tag-name der Fall ist (das ist komplexer, daher hoffe ich, es vermeiden zu können, aber wenn es der beste Weg ist, werde ich es in Betracht ziehen).

Der beste Ansatz hängt hier von Ihrem Endziel ab.

Wie stellen Sie sich das vor? Als Option in der Seitenleiste unter /search?

Hi @angus. Das Ziel ist es nicht, eine Suchabfrage in die seitliche Suchleiste einzufügen (das wäre zwar nett, ist aber hier nicht das Ziel). Das Ziel ist es, Themen basierend auf einem benutzerdefinierten Feld programmatisch in eine Topic-Liste zu laden, wenn der Benutzer eine Seite besucht. Ich denke, ich habe den Teil der Vorlage/Komponente (also die Ansicht) geklärt. Jetzt versuche ich, die Logik zu finden, die die Themen lädt.

Der Grund, warum ich über die Suche gesprochen habe, war meine Überlegung, dass ein Aufruf von ajax("/search") mit custom_field=Wert, wenn die Seite aufgerufen wird, ein sauberer Weg sein könnte, um die Themen zu laden. Aber ich versuche einfach, einen Weg zu finden, der am besten funktioniert.


Mehr Details:

In meinem Fall besteht das erste Ziel darin, dass der Benutzer zu einer neuen Vorlagenseite geht, die ich unter einem neuen Pfad erstellt habe (/fun_levels/:fun_level), und alle Themen mit dem benutzerdefinierten Feld fun_level lädt, das :fun_level entspricht.

Ich habe separat herausgefunden, wie man die Vorlage erstellt und unter dem Pfad lädt. Jetzt möchte ich die passenden Themen programmatisch in die Topic-Liste-Komponente laden, die ich auf der Seite habe.

Idealerweise würde ich vermeiden, ein neues „fun_level“-Modell erstellen zu müssen (was ich noch nicht getan habe), nur um die Dinge übersichtlicher zu halten und die Implementierung schneller zu gestalten. Aber ich bin dafür offen, wenn das unvermeidlich deutlich performanter sein wird (diese Seite wird häufig genutzt).


Es wäre auch gut zu wissen, wie man die Option hinzufügt, dass „fun_level“ eine Option in der Suchleiste ist – da ich das wahrscheinlich auch gerne haben würde. Und vielleicht ist der beste Weg, Themen basierend auf dem benutzerdefinierten Feld zu laden, das benutzerdefinierte Feld zu den Suchoptionen hinzuzufügen und dann ajax("/search") mit der Abfrage „fun_level: super-duper-fun“ aufzurufen.

Die Suchthemen könnten also hier wichtig sein. Aber die Hauptaufgabe im Moment ist es, beim Besuch einer Seite durch den Benutzer Themen basierend auf einem benutzerdefinierten Feld auf dieser Seite zu laden.

Soll sich diese Seite mit der Themenliste ähnlich wie bestehende Themenlisten-Seiten in Discourse anfühlen oder ist sie inhaltlich unterschiedlich?

2 „Gefällt mir“

Inhaltlich unterschiedlich. Der Fokus liegt hier jedoch lediglich darauf, wie man Themen mit einem benutzerdefinierten Feldwert (z. B. fun_level = ‘super-duper-fun’) in die Komponente {{topic-list topics=selectedTopics showPosters=true}} lädt, die ich in die Seite einfüge.

Wenn du mit Topic-Listen arbeitest, stellt sich die Frage, ob du die bestehende Discourse-Entdeckungsstruktur erweiterst oder eine eigene erstellst, was die Implementierung verändert. Es gibt viele verwandte Fragen zu dem, was du vorhast, die wir hier überspringen.

Wenn du die Entdeckungsstruktur also nicht erweiterst, wirst du den ersten Teil von dem, was ich oben vorgeschlagen habe, nicht durchführen. Du solltest jedoch den zweiten Teil weiterhin durchführen: das Hinzufügen des benutzerdefinierten Filters zu TopicQuery. Du benötigst auch eine Client-seitige Route mit einem Ajax-Aufruf an einen Endpunkt, der auf list_controller.rb abgebildet ist. Die Routen des List-Controllers findest du in config/routes.rb, indem du nach list# suchst.

Du solltest denselben Topic-Listen-Endpunkt verwenden, den die Discourse-Entdeckung nutzt, da du dann Dinge wie Paginierung (von „load-on-scroll

1 „Gefällt mir“

Danke für die Info.

Ich bin damit einverstanden, auf die einfachste Art und Weise die Themen abzurufen, die dem benutzerdefinierten Feldwert entsprechen. Ich habe bereits einen funktionierenden Route/Pfad/Template unter /fun_levels/:fun_level eingerichtet, der die {{topic-list}}-Komponente lädt. Wenn dieser Weg eine Suche nach dem benutzerdefinierten Feldwert über ajax(/search) beinhaltet, funktioniert das ebenfalls. Ich bin zunehmend der Meinung, dass dies der direkteste Weg ist. Ich habe das nur noch nicht zum Laufen gebracht.

Zur Klarstellung: Meine aktuelle Methode besteht darin,

  1. Themen per Ajax zurückzubekommen (ich muss nur noch herausfinden, was der richtige Endpunkt ist/wie man diesen Endpunkt einrichtet – das ist der Schlüssel),
  2. das Ergebnis zu parsen und
  3. component.set('showTopics', parsed-result) aufzurufen, um die Themen in {{topic-list topics=showTopics}} zu laden.

Diese Vorgehensweise erscheint mir etwas rätselhaft. Ich sehe die Methoden im list_controller, wie zum Beispiel def topics_by, aber wie könnte ich eine dieser Methoden so anpassen, dass sie Themen basierend auf einem benutzerdefinierten Feldwert zurückgibt?

Ich würde aus mehreren Gründen davon abraten. Es tut mir leid, mysteriös zu sein, aber es würde mehr Zeit in Anspruch nehmen, als ich im Moment habe, um das ausführlich zu erklären.

Der einfachste Weg ist die Verwendung eines der vorhandenen Endpunkte im Listen-Controller. Sie sind bereits so eingerichtet, dass sie Listen von Themen ausliefern. Sie finden sie in routes.rb, aber kurz gesagt sind es die Filter /latest, /top usw. Für eine Liste mit einem benutzerdefinierten Filter möchten Sie einen Abfrageparameter wie diesen verwenden:

/latest?fun_level=5

Verwendung des benutzerdefinierten Filters. Sie können die Klasse TopicQuery vom list_controller.rb aus verfolgen, um zu sehen, wie sie funktioniert. Sie fügt beispielsweise Ihren benutzerdefinierten Filter als unterstützten Parameter zum Controller hinzu. Der Grund, warum es sich mysteriös anfühlt, ist, dass dieser Controller und diese Klasse eine Reihe von Dingen für Sie übernehmen, wie z. B. Paginierung und verschiedene Filter, die Sie manuell einrichten müssten, wenn Sie es auf andere Weise tun.

Die „andere Möglichkeit“, die Sinn ergeben würde (nicht /search verwenden, denken Sie daran), besteht darin, einen eigenen dedizierten Controller für die Route einzurichten, der die Klasse TopicQuery ähnlich wie list_controller.rb verwendet. Sie müssen einen Rails-Controller erstellen, wenn Sie ohnehin eine völlig neue Route hinzufügen, daher ist dies ein weiterer plausibler Ansatz, wobei Sie jedoch Dinge wie die Paginierung selbst handhaben müssen. Wenn Sie diesen Ansatz verwenden, sollten Sie dennoch einen benutzerdefinierten Filter verwenden.

Ich verstehe, dass dies für einige undurchsichtig erscheinen mag, aber Sie haben es hier mit komplexer Funktionalität zu tun. Um dies vollständig zu erklären, müsste ich einen 10-teiligen Kurs schreiben. Das könnte ich tatsächlich bald tun :slight_smile:

2 „Gefällt mir“

UPDATE: Ich denke, es (größtenteils) funktioniert (!). Jetzt werden die „neuesten

4 „Gefällt mir“

Mit den oben genannten Anweisungen (dank an @angus und @JQ331) konnte ich erfolgreich die Themen abrufen, die einen Wert für das benutzerdefinierte Themenfeld haben, indem ich https://domain.com/latest?custom_field=custom_field_value besucht habe.

Wenn ich jedoch von dieser Seite aus auf das Website-Logo klicke (oder auf die Schaltfläche Neueste in der oberen Leiste), wird der Query-Parameter (custom_field) zwar aus der URL entfernt, aber die Themen bleiben nach custom_field gefiltert.

Beim Aktualisieren funktioniert die Seite wie erwartet (d. h. sie zeigt alle neuesten Themen an).

Wie kann ich dieses Verhalten beheben?

1 „Gefällt mir“