渲染大型 CSV 文档时,我们渲染一个
Enumerator
,它允许浏览器在创建文档时流式传输文档。 Enumerator
被传递到控制器 redner_csv 方法:
def render_csv(body:, filename:)
# Tell Rack to stream the content
headers.delete("Content-Length")
# Don't buffer when going through proxy servers
headers["X-Accel-Buffering"] = "no"
headers["Cache-Control"] = "no-cache"
headers["Last-Modified"] = Time.now.httpdate
headers["Content-Type"] = "text/csv; charset=utf-8; header=present"
headers["Content-Disposition"] = %(attachment; filename="#{filename}.csv")
self.response_body = body
end
这曾经有效,直到 Puma 6 现在在传递的枚举器上引发
undefined method `to_ary'
:
#<NoMethodError: undefined method `to_ary' for #<Enumerator: #<Enumerator::Generator:0x000000011e938568>:each>>
有人遇到这个问题吗?
我们可以使用 ActionController::Live#send_stream 方法解决该问题。之前,我们只是将主体设置为等于枚举器对象。
生成的代码:
def render_csv(body:, filename:)
headers["X-Accel-Buffering"] = "no"
headers["Cache-Control"] = "no-cache"
headers["Last-Modified"] = Time.now.httpdate
send_stream(filename: "#{filename}.csv") do |stream|
body.each {|line| stream.write line }
end
end