reopenWidget com chamada AJAX

Este é um tópico que surgiu várias vezes e estagnou (geralmente porque o dev não precisa realmente da chamada AJAX). No entanto, estou desenvolvendo um plugin que acessa dados não armazenados no banco de dados do Discourse (bot Discord autônomo) e estou tentando usar esses dados para decorar posts.

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);
        },
      });
    });
  },
});

Agora, tentei várias variações desse código, incluindo a chamada da função API na parte .then da consulta da store e assim por diante, e todas elas acabam da mesma forma, que é não renderizar as alterações nos posts até que você role a tela.

Todas essas tentativas foram feitas tarde da noite, então é definitivamente provável que eu esteja perdendo algo muito óbvio, no entanto, qualquer ajuda seria muito apreciada.

Depende do que você está tentando fazer, mas por que não usar a API oficial do Discord Ruby para obter os dados no banco de dados do Discourse, serializá-los para o cliente e, em seguida, usá-los no widget?

Parecia uma complexidade desnecessária quando a API das aplicações principais é boa o suficiente para a maioria das coisas, mas posso estar a interpretar mal a implementação, pois admitidamente terei de estudar um pouco mais o lado Ruby do discourse.

Embora, se não conseguir fazer a decoração de posts funcionar, provavelmente terei de seguir esse caminho.

Voltando para agradecer a @merefield, pesquisei mais sobre serialização e consegui realizar a tarefa fazendo a chamada da API no serializador em vez de solicitá-la do JS, como eu estava fazendo.

Tenho certeza de que há uma infinidade de razões pelas quais isso não é sugerido, mas funciona para mim, então estou seguindo em frente. Para aqueles que encontrarem isso no futuro, vocês podem inserir dados em um serializador com o seguinte 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

O que então permite que você acesse os dados dentro de uma chamada para reopenWidget. No meu caso, estou anexando os dados pertinentes ao tópico ao serializador topic_view e acessando-os enquanto modifico a postagem assim:

api.reopenWidget("post", {
          html(attrs) {
            let data_name = this.model.topic.data_name;

            // Faça algo com os dados

            return this.attach("post-article", attrs);
          },
        });

Como eu disse antes, provavelmente há muitas razões pelas quais essa não é a maneira correta de fazer isso, mas está funcionando para o meu caso de uso com impacto mínimo nos tempos de carregamento.

Para aqueles que desejam realizar a tarefa dentro do JS por qualquer motivo, o código pertinente parece existir no plugin discourse-encrypt, onde eles descriptografam postagens, mas achei este método muito mais fácil de implementar: discourse-encrypt/assets/javascripts/discourse/initializers/decrypt-posts.js at 255724ebc5fc3956f26beca09c1f7cb273d76eb2 · discourse/discourse-encrypt · GitHub

Estranhamente, isso parece quebrar o componente de tema Topic Thumbnails, tornando as imagens superdimensionadas GitHub - discourse/discourse-topic-thumbnails: Display thumbnails in topic lists

Realmente uma interação estranha, nada mais perceptível, no entanto.

Hmmm… Não tenho certeza se isso é arquiteturalmente sólido. Embora seja ótimo que você esteja explorando uma solução de back-end (chamadas de servidor remoto quase sempre devem ocorrer entre processos no back-end, especialmente onde autenticação e autorização estão envolvidas), os dados deveriam, argumentavelmente, carregar de forma assíncrona, e o serializador não deveria depender de uma chamada remota para ser concluída. No mínimo, você deveria envolver essa chamada em um cache?

Veja como você se sai, mas preste muita atenção ao tempo de carregamento da página antes e depois dessa alteração, você pode estar introduzindo um atraso significativo.

Na prática, isso adiciona entre 10-50ms por carregamento, se tanto. A conexão tem latência super baixa, pois ambas as caixas existem no mesmo data center. Na verdade, o método que estou usando para puxar dados para os componentes carrega as páginas marginalmente mais rápido do que o Discourse renderiza suas próprias páginas estáticas (diferença de cerca de 100ms), e isso inclui uma operação de banco de dados que usa IDs do Discord para adicionar dados do usuário às respostas da API antes que sejam encaminhadas para o cliente. (Ruby solicita dados da Aplicação Externa → Analisa JSON → Loop each de consulta ao banco de dados para anexar dados à resposta → Gera JSON e retorna ao cliente frontend). É compreensível considerando o quão grande é a base de código, mas definitivamente há uma sobrecarga interna que abre espaço para que essas requisições, tradicionalmente vistas como “caras”, passem completamente despercebidas. Dito isso, estamos falando da velocidade da luz e do som aqui, que para o usuário final ainda é incrivelmente rápido, pois o Discourse é uma plataforma incrível.

Um cache seria uma ótima adição e algo que vou investigar, sou muito novo em Ruby, então atualizarei conforme aprender mais sobre as funções disponíveis. Vou atualizar isso conforme avanço, porque acho que algum tipo de método para isso, embora improvisado no momento, pode ser potencialmente muito benéfico para o lado do desenvolvimento de plugins. Para pessoas com aplicações existentes, poder usar a API que conhecem para inserir os dados de que precisam onde precisam de forma eficiente, sem ter que construir sistemas para sincronizar dados entre seu banco de dados e o Discourse ou mexer com modelos adicionais ou migrações de banco de dados, reduz drasticamente o tempo de desenvolvimento e mantém os autores de plugins em algumas das áreas melhor documentadas da aplicação (ou seja, a API de Plugins).

Agradeço muito a visão, definitivamente animado para continuar aprendendo mais sobre esta plataforma e espero contribuir no futuro.

3 curtidas

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.