使用 AJAX 调用重新打开 Widget

这是一个反复出现并停滞不前的主题(通常是因为开发人员实际上不需要 AJAX 调用)。但是,我正在开发一个插件,该插件访问不存储在 Discourse 数据库中的数据(独立的 Discord 机器人),并且我正试图使用该数据来装饰帖子。

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

现在,我已经尝试了此代码的不同变体,包括在 store 查询的 .then 部分中调用 api 函数等等,但它们都以相同的方式结束,即在滚动帖子时更改才渲染出来。

所有这些尝试都是在深夜进行的,所以我很可能遗漏了一些非常明显的东西,但是,任何帮助都将不胜感激。

这取决于您想做什么,但我认为为什么不使用官方的 Discord Ruby API 将数据导入 Discourse 数据库,然后将其序列化到客户端,再在小部件中使用呢?

似乎是不必要的复杂性,因为主要应用程序的 API 对大多数事情来说已经足够了,但我可能误解了实现,因为我承认我需要更多地研究 Discourse 的 Ruby 部分。

不过,如果我无法实现帖子的装饰功能,我可能会走那条路。

感谢 @merefield 的建议,我进一步研究了序列化,并通过在序列化器中进行 API 调用而不是像之前那样从 JS 请求,成功完成了任务。

我确信有很多原因不建议这样做,但它对我来说是有效的,所以我将继续使用它。对于将来遇到此问题的人,您可以使用以下代码将数据推送到序列化器:

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

这使得您可以在调用 reopenWidget 时访问数据。在我的例子中,我将与主题相关的数据附加到 topic_view 序列化器中,并在修改帖子时访问它,如下所示:

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

            // Do stuff with data

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

正如我之前所说,这可能有很多原因不是正确的方法,但它对我的用例有效,并且对加载时间的影响很小。

对于那些出于任何原因希望在 JS 中完成任务的人,相关的代码似乎存在于 discourse-encrypt 插件中,他们可以在其中解密帖子,但我发现这种方法更容易实现:discourse-encrypt/assets/javascripts/discourse/initializers/decrypt-posts.js at 255724ebc5fc3956f26beca09c1f7cb273d76eb2 · discourse/discourse-encrypt · GitHub

奇怪的是,这似乎会破坏 Topic Thumbnails 主题组件,使图片变得超大 GitHub - discourse/discourse-topic-thumbnails: Display thumbnails in topic lists

这真是一个奇怪的交互,除此之外没有其他明显的问题。

嗯……我不确定这在架构上是否合理。虽然很高兴您正在探索后端解决方案(尤其是在涉及身份验证和授权的情况下,远程服务器调用几乎总应该发生在后端进程之间),但数据应该异步加载,并且序列化器不应依赖远程调用来完成。至少您应该将该调用包装在缓存中?

看看您的进展,但要密切注意更改前后页面的加载时间,您可能会引入显著的延迟。

实际上,每次加载只会增加 10-50 毫秒的延迟。由于两个服务器位于同一数据中心,连接的延迟非常低。事实上,我用来将数据拉入组件的方法加载页面的速度比 Discourse 渲染自己的静态页面还要快(大约快 100 毫秒),这包括了一个使用 Discord ID 将用户数据添加到 API 响应中,然后再转发给客户端的数据库操作。(Ruby 从外部应用程序请求数据 → 解析 JSON → 数据库查询。each 循环将数据附加到响应 → 生成 JSON 并返回给前端客户端)。考虑到代码库的庞大,这是可以理解的,但内部确实存在一些开销,使得这些传统上被认为是“昂贵”的请求完全不被注意。话虽如此,我们这里谈论的是光速和声速,对最终用户来说仍然非常快,因为 Discourse 是一个很棒的平台。

缓存将是一个很好的补充,我也会进行研究,我对 Ruby 还很陌生,所以我会随着对可用函数的了解更多而进行更新。我将继续更新,因为我认为某种方法,尽管目前有些笨拙,但可能对插件开发非常有益。对于拥有现有应用程序的人来说,能够使用他们熟悉的 API 将所需数据高效地放到需要的地方,而无需构建系统来同步他们数据库和 Discourse 之间的数据,或者处理额外的模型或数据库迁移,可以大大缩短开发时间,并让插件作者留在应用程序中一些文档记录更好的区域(即插件 API)。

我非常感谢您的见解,我非常期待继续了解这个平台,并希望将来能做出贡献。

3 个赞

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