You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rails游戏项目:如何从Scheduler.rb触发HTML事件更新香蕉状态

解决Rails后端Scheduler线程触发前端HTML事件的方案

嘿,这个场景我之前碰到过——后端异步线程完成状态更新后,要主动通知前端触发对应的交互,对吧?核心问题是后端无法直接触发前端事件,得通过前后端通信的方式来实现,下面给你几个适配Rails项目的可行方案:

方案1:用Action Cable(WebSocket实时推送)

这是最适合实时场景的方案,Rails官方提供的WebSocket框架,能让后端主动给前端发消息。

步骤拆解:

  1. 创建更新通知Channel
    先生成一个Channel来处理香蕉更新的广播:

    rails generate channel BananaUpdates
    

    然后在app/channels/banana_updates_channel.rb里写广播逻辑:

    class BananaUpdatesChannel < ApplicationCable::Channel
      def subscribed
        # 可以按花园或者用户订阅,这里假设按花园ID分组
        stream_from "banana_updates_#{params[:garden_id]}"
      end
    
      def unsubscribed
        # 清理逻辑,可选
      end
    
      # 提供给Scheduler调用的广播方法
      def self.broadcast_banana_update(garden_id, banana)
        broadcast_to "banana_updates_#{garden_id}", {
          banana_id: banana.id,
          ripeness: banana.ripeness,
          action: "update_ripeness"
        }
      end
    end
    
  2. 在Scheduler.rb里触发广播
    当香蕉成熟度更新完成后,调用上面的广播方法:

    # Scheduler.rb中更新香蕉成熟度的逻辑里
    banana.update(ripeness: new_ripeness, nexttime: next_update_time)
    # 广播更新事件到对应花园的Channel
    BananaUpdatesChannel.broadcast_banana_update(banana.garden_id, banana)
    

    注意:如果Scheduler是独立线程,要确保线程能正确访问Rails的环境(比如数据库连接),可以在线程初始化时加载Rails环境,或者用Rails.application.executor.wrap包裹操作。

  3. 前端订阅Channel并触发HTML事件
    在前端的JS文件(比如app/javascript/channels/banana_updates.js)里订阅消息,收到后触发自定义HTML事件:

    import consumer from "./consumer"
    
    consumer.subscriptions.create({ channel: "BananaUpdatesChannel", garden_id: YOUR_GARDEN_ID }, {
      received(data) {
        // 触发自定义HTML事件,比如给对应的香蕉元素发事件
        const bananaElement = document.getElementById(`banana-${data.banana_id}`);
        if (bananaElement) {
          const updateEvent = new CustomEvent("bananaRipenessUpdated", {
            detail: { ripeness: data.ripeness }
          });
          bananaElement.dispatchEvent(updateEvent);
        }
      }
    });
    
    // 监听自定义事件,执行你需要的操作
    document.addEventListener("bananaRipenessUpdated", (e) => {
      // 比如更新香蕉图标、显示提示等
      console.log("香蕉成熟度更新了:", e.detail.ripeness);
      // 这里写你的HTML事件逻辑,比如切换图标类名
      e.target.classList.add(`ripe-${e.detail.ripeness}`);
    });
    

方案2:用Turbo Streams(适合Rails 7+ Hotwire项目)

如果你的项目用了Hotwire/Turbo,这个方案更简洁,不需要写太多JS代码。

步骤:

  1. Scheduler里广播Turbo Stream
    当香蕉更新完成后,直接广播Turbo Stream片段,既可以更新DOM,也能触发事件:

    # Scheduler.rb中
    banana.update(ripeness: new_ripeness, nexttime: next_update_time)
    
    # 广播一个自定义动作,触发前端事件
    Turbo::StreamsChannel.broadcast_action_to(
      "banana_updates_#{banana.garden_id}",
      action: "dispatch_event",
      target: "banana-#{banana.id}",
      event: "bananaRipenessUpdated",
      data: { ripeness: banana.ripeness }.to_json
    )
    
  2. 前端页面订阅Stream
    在你的花园视图页面里添加订阅:

    <%= turbo_stream_from "banana_updates_#{@garden.id}" %>
    

    然后在JS里监听自定义事件即可,和方案1的前端监听逻辑一样。

方案3:轮询(简单但非实时)

如果不想搞WebSocket,也可以用前端定时轮询后端接口,检查香蕉状态,有更新就触发事件。这种方式适合对实时性要求不高的场景:

前端示例:

setInterval(async () => {
  const response = await fetch(`/gardens/${YOUR_GARDEN_ID}/bananas/status`);
  const updatedBananas = await response.json();
  
  updatedBananas.forEach(banana => {
    const bananaElement = document.getElementById(`banana-${banana.id}`);
    if (bananaElement && bananaElement.dataset.ripeness !== banana.ripeness) {
      bananaElement.dataset.ripeness = banana.ripeness;
      // 触发事件
      bananaElement.dispatchEvent(new CustomEvent("bananaRipenessUpdated", { detail: banana }));
    }
  });
}, 5000); // 每5秒轮询一次

后端要加对应的接口:

# app/controllers/bananas_controller.rb
def status
  @garden = Garden.find(params[:garden_id])
  @bananas = @garden.bananas.select(:id, :ripeness)
  render json: @bananas
end

注意事项

  • 独立线程的Scheduler要确保线程安全,比如数据库连接的释放,避免连接泄漏。可以用ActiveRecord::Base.connection_pool.with_connection包裹数据库操作。
  • 如果用Action Cable,要确保Redis(或其他适配器)配置正确,因为Action Cable默认用Redis做广播。

内容的提问来源于stack exchange,提问作者user9675688

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:46:38