Ciao a tutti,
Sto sviluppando un plugin per lotterie per Discourse in cui gli utenti possono partecipare rispondendo a un argomento della lotteria. In piena trasparenza: non sono un programmatore, sto costruendo questo interamente con l’assistenza dell’IA (Claude Code), quindi potrei trascurare concetti fondamentali. La funzionalità di base funziona, ma ho problemi con gli aggiornamenti in tempo reale utilizzando MessageBus. Apprezzerei qualsiasi guida sull’approccio corretto.
Cosa sto cercando di ottenere
- Creare un post della lotteria utilizzando BBCode
[lottery]...[/lottery] - Visualizzare una scheda della lotteria nel post che mostra il conteggio dei partecipanti
- Quando gli utenti rispondono per partecipare, tutti gli spettatori dovrebbero vedere il conteggio dei partecipanti aggiornarsi in tempo reale senza aggiornamento della pagina
- Simile a come il plugin discourse-calendar aggiorna le informazioni sugli eventi
Implementazione attuale
Backend (Ruby)
Modello Lottery (app/models/lottery.rb):
def publish_update!
channel = "/lottery/#{self.post.topic_id}"
message = { id: self.id }
MessageBus.publish(channel, message)
end
Modello LotteryParticipant (app/models/lottery_participant.rb):
after_commit :publish_lottery_update, on: [:create, :destroy]
private
def publish_lottery_update
self.lottery.publish_update!
end
I log del backend confermano che MessageBus.publish viene chiamato con successo:
[Lottery] 📡 Publishing MessageBus update:
Channel: /lottery/27
Message: {:id=>52}
[Lottery] ✅ MessageBus.publish completed
Frontend (JavaScript)
Decorator (discourse-lottery-decorator.gjs):
api.decorateCookedElement((cooked, helper) => {
const post = helper.getModel();
if (!post?.lottery_data) return;
// Check if already decorated (AI suggested using data attribute)
if (cooked.dataset.lotteryDecorated === "true") return;
const lotteryNode = cooked.querySelector(".discourse-lottery");
if (!lotteryNode) return;
const wrapper = document.createElement("div");
lotteryNode.before(wrapper);
const lottery = Lottery.create(post.lottery_data);
helper.renderGlimmer(
wrapper,
`<template><DiscourseLottery @lotteryData={{lottery}} /></template>`
);
lotteryNode.remove();
cooked.dataset.lotteryDecorated = "true";
}, { id: "discourse-lottery" });
Component (discourse-lottery/index.gjs):
export default class DiscourseLottery extends Component {
@service messageBus;
@service lotteryApi;
constructor() {
super(...arguments);
const { lotteryData } = this.args;
if (lotteryData?.topicId) {
this.lotteryPath = `/lottery/${lotteryData.topicId}`;
this.lotteryData = lotteryData;
// AI suggested manually binding the callback
this._boundOnLotteryUpdate = this._onLotteryUpdate.bind(this);
this.messageBus.subscribe(this.lotteryPath, this._boundOnLotteryUpdate);
registerDestructor(this, () => {
this.messageBus.unsubscribe(this.lotteryPath, this._boundOnLotteryUpdate);
});
}
}
async _onLotteryUpdate(msg) {
console.log('[Lottery Component] 🔔 MessageBus message received!');
const updatedData = await this.lotteryApi.lottery(this.lotteryData.topicId);
this.lotteryData.updateFromLottery(updatedData);
}
}
Model (models/lottery.js):
export default class Lottery {
@tracked _stats;
set stats(stats) {
this._stats = LotteryStats.create(stats || {});
}
updateFromLottery(lottery) {
// Update all properties including stats
this.stats = lottery.stats || {};
// ... other properties
}
}
Il problema
Solo la pagina del partecipante si aggiorna in tempo reale, ma le pagine degli altri spettatori non si aggiornano senza refresh.
Cosa funziona:
Quando un utente risponde per partecipare, la sua pagina mostra l’aggiornamento in tempo reale del conteggio dei partecipanti
Il backend pubblica messaggi MessageBus con successo
Il messaggio MessageBus viene ricevuto sulla pagina del partecipante (i log mostrano “
MessageBus message received!”)
Il modello viene aggiornato con il nuovo conteggio dei partecipanti (i log mostrano il conteggio aumentare da 0 a 1)
Cosa non funziona:
Gli altri spettatori che guardano l’argomento della lotteria non vedono il conteggio aggiornarsi in tempo reale
La pagina del creatore della lotteria non si aggiorna
La pagina di qualsiasi altro utente che ha aperto l’argomento della lotteria non si aggiorna- Tutti devono aggiornare manualmente la pagina per vedere il conteggio aggiornato dei partecipanti
Inoltre, vedo il componente che viene distrutto e ricreato più volte nella console:
[Lottery Component] ✅ MessageBus subscription established
[Lottery Component] 🧹 Cleaning up MessageBus for topic: 27
[Lottery Component] ✅ MessageBus subscription established
[Lottery Component] 🧹 Cleaning up MessageBus for topic: 27
Ciò suggerisce che decorateCookedElement viene attivato più volte, causando la distruzione e la ricreazione dei componenti, il che potrebbe interrompere la sottoscrizione MessageBus per gli altri spettatori.
Domande
-
L’utilizzo dell’attributo
data-decoratedsull’elemento cotto è il modo corretto per prevenire decorazioni duplicate? L’IA ha suggerito questo approccio, ma non ho trovato documentazione ufficiale che lo confermi come pattern consigliato. -
Perché l’interfaccia utente non si aggiorna anche se la proprietà del modello tracciata cambia? La
@tracked _statsdovrebbe attivare il re-render quando aggiornata tramitethis.stats = lottery.stats, ma il conteggio dei partecipanti visualizzato rimane lo stesso. C’è qualcosa che non va nel modo in cui utilizzo@tracked? -
Dovrei utilizzare un approccio completamente diverso? Ho chiesto all’IA di seguire il modello discourse-calendar, ma forse mi sfugge qualcosa di fondamentale su come Discourse gestisce gli aggiornamenti in tempo reale.
-
La rimozione di
lotteryNodeoriginale causa il problema? L’IA inizialmente ha provato a non rimuoverlo, ma ciò ha causato la scomparsa della scheda della lotteria a causa del CSS (.cooked > .discourse-lottery { display: none; }). Esiste un pattern migliore?
Dato che non sono un programmatore, potrei fare domande basilari - qualsiasi indicazione su documentazione o esempi sarebbe incredibilmente utile! Grazie!