我的rails应用程序中有一个ajax请求,该请求从我的 Controller 操作返回一个变量。在 Controller Action 内部,我有一个循环,可能需要一些时间才能完成。

Controller

def myAction
  $j = 1
  until $j > list_size do
    array <<  {  :foo => $j }
    $j +=1;
  end
  @myvariable = array.to_json
end

myAction.js.erb
 var myVariable = JSON.parse("<%= escape_javascript(raw @myvariable) %>");
 for (var k = 0; k < myVariable.length; k++) {
   $("#myDiv").append(myVariable[k].foo);
 }

我希望能够在循环的每个阶段将结果呈现给js.erb部分,而不是等待循环完成。在不中断循环并在循环结束之前过早结束操作的情况下,这是否可能?也许像这样(错误的伪代码):

Controller
def myAction
  $j = 1
  until $j > list_size do
    array <<  {  :foo => $j }
    render array.to_json
    $j +=1;
  end
end

myAction.js.erb
 var myVariable = JSON.parse("<%= escape_javascript(raw @myvariable) %>");
 $("#myDiv").append(myVariable.foo);

最佳答案

render stream: true将延迟加载查询,并在呈现 Assets 和布局后允许它们运行。流仅适用于模板,不适用于任何其他形式(例如json或xml)。

因此,您不走运,您将不得不使用Rail 4及更高版本中可用的ActionController::Live。 Live是ActionController类中包含的一个特殊模块。它使Rails可以显式打开和关闭流。这是经过修改的伪代码,使其更像 ruby ,并且避免了全局变量:

class MyController < ActionController::Base
  include ActionController::Live
  def action
    (1..list_size).each do |list_item|
      response.stream.write("{  "foo": #{list_item} }")
    end
  ensure
     response.stream.close
  end
end

上面的代码将从1循环到list_size,并立即将每个list_item 输出

若要使用此功能,则应使用服务器发送的事件。通常,网页必须询问是否有任何更新。使用服务器发送的事件,更新会自动出现。

请使用以下资源来了解有关流,SSE和事件源的更多信息:
  • API Docs -ActionController::Live
  • RailscastPaid
  • Is it live
  • Streaming with Rails 4
  • Server-sent events - Wikipedia
  • SEE on client side @html5rocks
  • 09-10 05:36
    查看更多