在Rails中使用轮询刷新多个部分

问题描述 投票:1回答:1

假设我有一个可能如下所示的状态列表:

ul#list
  - @list_items.each do |item|
    li.loading Item #{item.id} - Status: #{item.status}
    li Item #{item.id} - Status: #{item.status}
    li Item #{item.id} - Status: #{item.status}
    li.loading Item #{item.id} - Status: #{item.status}

这让我:

Item 1 - Status: Loading
Item 2 - Status: Finished
Item 3 - Status: Finished
Item 4 - Status: Loading

我想要做的是定期轮询各个列表项的更改,并在状态发生变化时刷新它们。到目前为止,我能够通过刷新整个列表来逃脱:

ul#list
  == render 'status_list', list_items: @list_items

咖啡:

if $('.loading').length > 0
  setInterval (=>
    @refreshListPartial()
  ), 5000

其中@refreshListPartial是一个AJAX函数,它击中Rails控制器,然后继续刷新整个列表部分:

$("#list").html("<%= escape_javascript(render partial: 'status_list', locals: { list_items: @list_items } ) %>");

但是如何才能检查页面上individual列表项的状态并仅刷新它们?我知道React对于这个任务来说可能是一个更容易的解决方案,但是甚至可以用Rails完成而不用跳过十几个篮球?我想到的另一件事是ActionCable(我正在使用Rails 5),但为这个功能打开perma连接似乎是一种矫枉过正,我宁愿选择轮询。

更新

只是大声思考。因此,要刷新多个部分而不是一个,我需要在我的.js.erb文件中到达此部分:

<%- @items.each do |item| %>
  $("#list-item-<%= item.id %>").html("<%= escape_javascript(render partial: 'item', locals: { list_item: item } ) %>");
<% end %>

该视图现在应该如下所示:

ul#list
  @list_items.each do |item|
    == render 'list_item', list_item: @list_item

那么剩下的是ajax函数,它应该获取需要刷新的列表项的id'并将它们作为数组发送到控制器。

javascript jquery ruby-on-rails ajax ruby-on-rails-5
1个回答
0
投票

我最终在问题更新中对我自己提出的内容进行了扩展。

前端代码,用于检查是否需要根据数据标记刷新某些部分:

class JobRequestPartialReload
  constructor: ->
    checkForRunningJobs = ->
      if $('.poll_for_changes').length > 0
        @arr = []
        $('.poll_for_changes').each (index, element) =>
            @arr.push(element.closest('[data-id]').dataset.id)
        sendDataToRails()

    sendDataToRails = ->
      $.ajax
        url: "/jobs/refresh_list"
        method: "POST"
        data: {jobRequestList: @arr}

    setInterval (=>
      checkForRunningJobs()
    ), 10000

$(document).on 'turbolinks:load', new JobRequestPartialReload

控制器:

  def refresh_list
    ajax_data = params[:jobRequestList].map(&:to_i)
    @job_requests = JobRequest.includes(...).where(id: ajax_data)

    respond_to do |format|
      format.js
    end
  end

最后,JS.erb文件:

<% @job_requests.each do |job| %>
  <% case job.state %>
  <% when 'initiated' %>
    // don't care
  <% when 'active' %>
    visibleStatus = $('#job-id-<%= job.id %> .status-list').text()
    if (visibleStatus == 'initiated') {
      $('#job-id-<%= job.id %>').html("<%= escape_javascript(render partial: 'job_requests/shared/job_request', locals: { job: job } ) %>");
  <% else %>
    // failed, completed, etc.
    $('#job-id-<%= job.id %>').html("<%= escape_javascript(render partial: 'job_requests/shared/job_request', locals: { job: job } ) %>");
  <% end %>
<% end %>

回答更新

我后来添加了js代码,用于检查某些部分是否在实际用户视口中,并且仅以5-10秒的速率检查它们。这大大减少了每个客户端发送的查询数量。

© www.soinside.com 2019 - 2024. All rights reserved.