Este es un tema que ha surgido varias veces y se ha estancado (generalmente porque el desarrollador en realidad no requiere la llamada AJAX). Sin embargo, estoy desarrollando un plugin que accede a datos que no están almacenados en la base de datos de Discourse (un bot de Discord autónomo) y estoy intentando usar esos datos para decorar publicaciones.
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);
},
});
});
},
});
Ahora he probado diferentes variaciones de este código, incluida la llamada a la función de la API en la parte .then de la consulta de la tienda y demás, y todas terminan igual, que es no renderizar los cambios en las publicaciones hasta que te desplazas.
Todos estos intentos se hicieron tarde en la noche, así que es muy probable que me esté perdiendo algo súper obvio, sin embargo, cualquier ayuda sería muy apreciada.
Depende de lo que estés intentando hacer, supongo, pero ¿por qué no usar la API oficial de Discord Ruby para obtener los datos en la base de datos de Discourse, serializarla al cliente y luego usarla en el widget?
Parecía una complejidad innecesaria cuando la API de las aplicaciones principales es lo suficientemente buena para la mayoría de las cosas, pero podría estar malinterpretando la implementación, ya que, ciertamente, necesitaré estudiar un poco más el lado de Ruby de Discourse.
Aunque si no puedo hacer que la decoración de publicaciones funcione, probablemente tendré que seguir ese camino.
Volviendo para agradecer a @merefield, investigué más sobre la serialización y pude completar la tarea haciendo la llamada a la API en el serializador en lugar de solicitarla desde JS como lo estaba haciendo.
Estoy seguro de que hay una plétora de razones por las que esto no se sugiere, pero funciona para mí, así que lo estoy implementando. Para aquellos que encuentren esto en el futuro, pueden insertar datos en un serializador con el siguiente código:
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
Lo que luego le permite acceder a los datos dentro de una llamada a reopenWidget. En mi caso, estoy adjuntando los datos pertinentes al tema al serializador topic_view y accediendo a ellos mientras modifico la publicación de la siguiente manera:
api.reopenWidget("post", {
html(attrs) {
let data_name = this.model.topic.data_name;
// Hacer cosas con los datos
return this.attach("post-article", attrs);
},
});
Como dije antes, probablemente haya un montón de razones por las que esta no es la forma correcta de hacerlo, pero está funcionando para mi caso de uso con un impacto mínimo en los tiempos de carga.
Hmmm… No estoy seguro de que eso sea arquitectónicamente sólido. Si bien es genial que estés explorando una solución de back-end (las llamadas al servidor remoto casi siempre deberían ocurrir entre procesos en el back-end, especialmente cuando hay autenticación y autorización involucradas), los datos deberían cargarse asincrónicamente y el serializador no debería depender de que una llamada remota termine para concluir. ¿Como mínimo, deberías envolver esa llamada en una caché?
Mira cómo te va, pero presta mucha atención al tiempo de carga de la página antes y después de ese cambio, podrías estar introduciendo un retraso significativo.
En la práctica, añade entre 10 y 50 ms por carga, si acaso. La conexión tiene una latencia súper baja, ya que ambas máquinas existen en el mismo centro de datos. De hecho, el método que estoy utilizando para incorporar datos a los componentes carga las páginas marginalmente más rápido que si Discourse renderizara sus propias páginas estáticas (diferencia de unos 100 ms), y eso incluye una operación de base de datos que utiliza ID de Discord para añadir datos de usuario a las respuestas de la API antes de que se reenvíen al cliente. (Ruby solicita datos de la Aplicación Externa → Analiza JSON → Bucle each de consulta a la base de datos para añadir datos a la respuesta → Genera JSON y lo devuelve al cliente frontend). Es comprensible, considerando lo grande que es la base de código, pero definitivamente hay una sobrecarga interna que deja espacio para que estas solicitudes, tradicionalmente consideradas “costosas”, pasen completamente desapercibidas. Dicho esto, estamos hablando de la velocidad de la luz y el sonido aquí, que para el usuario final sigue siendo increíblemente rápido, ya que Discourse es una plataforma asombrosa.
Una caché sería una gran adición y será algo que investigaré, soy muy nuevo en Ruby, así que actualizaré a medida que aprenda más sobre las funciones disponibles. Voy a actualizar esto a medida que avance, porque creo que algún tipo de método para esto, aunque sea un hack en este momento, podría ser potencialmente muy beneficioso para el lado del desarrollo de plugins. Para las personas con aplicaciones existentes, poder usar la API que conocen para deslizar los datos que necesitan donde los necesitan de manera eficiente sin tener que construir sistemas para sincronizar datos entre su base de datos y Discourse o jugar con modelos adicionales o migraciones de bases de datos, reduce drásticamente el tiempo de desarrollo y mantiene a los autores de plugins en algunas de las áreas mejor documentadas de la aplicación (es decir, la API de Plugins).
Agradezco enormemente la perspectiva, definitivamente estoy emocionado de seguir aprendiendo más sobre esta plataforma y, con suerte, contribuir en el futuro.