Dies ist ein Thema, das mehrmals aufgetaucht und ins Stocken geraten ist (normalerweise, weil der Entwickler den AJAX-Aufruf nicht wirklich benötigt). Ich entwickle jedoch ein Plugin, das auf Daten zugreift, die nicht in der Discourse-Datenbank gespeichert sind (ein in sich geschlossener Discord-Bot), und ich versuche, diese Daten zum Dekorieren von Beiträgen zu verwenden.
export default Component.extend({
init() {
this._super(...arguments);
var self = this;
const store = getOwner(this).lookup("service:store");
let positions = [];
store
.findAll("position", {
...args,
})
.then((data) => {
for (const [key, position] of Object.entries(data.content)) {
positions.pushObject(EmberObject.create({ ...position }));
}
});
withPluginApi("1.4.0", (api) => {
api.reopenWidget("post", {
html(attrs) {
let position = positions.filter(
(position) => position.user.id == attrs.user.id
);
if (position.length > 0) {
attrs.cooked = "Has Position";
}
return this.attach("post-article", attrs);
},
});
});
},
});
Ich habe verschiedene Variationen dieses Codes ausprobiert, einschließlich des API-Funktionsaufrufs im .then-Teil der Store-Abfrage und so weiter, und sie enden alle auf die gleiche Weise, nämlich dass die Änderungen an den Beiträgen erst angezeigt werden, wenn man herumscrollt.
All diese Versuche wurden spät in der Nacht gemacht, daher ist es sehr wahrscheinlich, dass ich etwas ganz Offensichtliches übersehe, aber jede Hilfe wäre sehr willkommen.
Hängt davon ab, was Sie zu tun versuchen, aber warum nicht die offizielle Discord Ruby API verwenden, um die Daten in die Discourse-Datenbank zu bekommen, sie an den Client zu serialisieren und sie dann im Widget zu verwenden?
Schien unnötige Komplexität zu sein, wenn die API der primären Anwendungen für die meisten Dinge gut genug ist, aber ich könnte die Implementierung missverstehen, da ich zugeben muss, dass ich die Ruby-Seite von Discourse noch etwas genauer studieren muss.
Obwohl, wenn ich die Beitragsdekoration nicht zum Laufen bringe, werde ich wahrscheinlich diesen Weg einschlagen müssen.
Nochmals vielen Dank an @merefield. Ich habe mich weiter mit der Serialisierung beschäftigt und die Aufgabe gelöst, indem ich den API-Aufruf im Serializer statt in JavaScript, wie ich es zuvor getan hatte, vorgenommen habe.
Ich bin sicher, dass es eine Fülle von Gründen gibt, warum dies nicht empfohlen wird, aber es funktioniert für mich, also bleibe ich dabei. Für diejenigen, die dies in Zukunft finden, können Sie Daten mit dem folgenden Code in einen Serializer einfügen:
add_to_serializer(:topic_view, :data_name) do
JSON.parse(Net::HTTP.get(URI('https://yourwebsite.com?topic_id=' + object.topic.id.to_s)))
end
Dies ermöglicht es Ihnen dann, auf die Daten innerhalb eines Aufrufs von reopenWidget zuzugreifen. In meinem Fall füge ich die für das Thema relevanten Daten dem Topic-View-Serializer hinzu und greife darauf zu, während ich den Beitrag wie folgt modifiziere:
api.reopenWidget("post", {
html(attrs) {
let data_name = this.model.topic.data_name;
// Mache etwas mit den Daten
return this.attach("post-article", attrs);
},
});
Wie ich bereits sagte, gibt es wahrscheinlich viele Gründe, warum dies nicht der richtige Weg ist, aber es funktioniert für meinen Anwendungsfall mit minimalen Auswirkungen auf die Ladezeiten.
Hmmm … Ich bin mir nicht sicher, ob das architektonisch solide ist. Obwohl es großartig ist, dass Sie eine Backend-Lösung (Remote-Serveraufrufe sollten fast immer zwischen Prozessen im Backend erfolgen, insbesondere wenn Authentifizierung und Autorisierung beteiligt sind) untersuchen, sollte die Daten wohl asynchron geladen werden, und der Serialisierer sollte sich nicht darauf verlassen, dass ein Remote-Aufruf abgeschlossen ist, um zu enden. Zumindest sollten Sie diesen Aufruf in einen Cache packen?
Sehen Sie, wie Sie damit zurechtkommen, aber achten Sie genau auf das Timing des Ladens der Seite vor und nach dieser Änderung, Sie könnten eine erhebliche Verzögerung einführen.
In der Praxis sind es höchstens 10-50 ms pro Ladevorgang. Die Verbindung hat eine extrem geringe Latenz, da sich beide Systeme im selben Rechenzentrum befinden. Tatsächlich lädt die Methode, mit der ich Daten in Komponenten abrufe, Seiten geringfügig schneller als Discourse seine eigenen statischen Seiten rendert (ein Unterschied von etwa 100 ms), und das schließt eine Datenbankoperation ein, die Discord-IDs verwendet, um Benutzerdaten in die API-Antworten einzufügen, bevor sie an den Client weitergeleitet werden. (Ruby fordert Daten von externer Anwendung an → JSON parsen → DB-Abfrage.each-Schleife zum Anhängen von Daten an die Antwort → JSON generieren und an den Frontend-Client zurückgeben). Das ist verständlich, wenn man bedenkt, wie groß die Codebasis ist, aber es gibt definitiv einen internen Overhead, der Raum für diese Anfragen schafft, die traditionell als „teuer“ angesehen werden und völlig unbemerkt bleiben. Dennoch sprechen wir hier von Lichtgeschwindigkeit und Schall, was für den Endbenutzer immer noch unglaublich schnell ist, da Discourse eine erstaunliche Plattform ist.
Ein Cache wäre eine großartige Ergänzung und etwas, das ich mir ansehen werde. Ich bin noch sehr neu in Ruby und werde dies aktualisieren, sobald ich mehr über die verfügbaren Funktionen gelernt habe. Ich werde dies im Laufe der Zeit aktualisieren, da ich glaube, dass eine Art Methode dafür, wenn auch im Moment etwas umständlich, für die Plugin-Entwicklung potenziell sehr vorteilhaft sein könnte. Für Personen mit bestehenden Anwendungen kann die Verwendung der ihnen bekannten API, um die benötigten Daten effizient dorthin zu verschieben, wo sie benötigt werden, ohne Systeme zum Synchronisieren von Daten zwischen ihrer Datenbank und Discourse aufbauen zu müssen oder sich mit zusätzlichen Modellen oder Datenbankmigrationen herumschlagen zu müssen, die Entwicklungszeit drastisch verkürzen und Plugin-Autoren in einigen der besser dokumentierten Bereiche der Anwendung (d. h. der Plugin-API) halten.
Ich schätze die Einblicke sehr und bin definitiv begeistert, mehr über diese Plattform zu lernen und hoffentlich in Zukunft dazu beizutragen.