I have an external process that takes a while and emits lines. I’d like to send those lines back to the browser as they happen.
I can’t work out how to do this.
I’ve got this so far, and whilst I can see the lines being processed new line: x
- All the turbo updates are just delivered at the end.
I’ve been hunting for a “flush” operation on the response.stream
but can’t find anything…
Thanks in advance.
# show.erb at /show
<%= link_to "DO IT", "/stream", data: {turbo_stream: true} %>
<div id="output">
</div>
# Controller at /stream
def stream
response.headers["Content-Type"] = "text/vnd.turbo-stream.html"
begin
# Start the external program
IO.popen(["ruby", "-e", "$stdout.sync = true", "-e", "(1..5).each { |l| puts(l); sleep 1 }"], "r") do |program_output|
program_output.each_line do |line|
pp "new line: " + line
# Stream each line as a Turbo Stream update
response.stream.write turbo_stream.append(
"output", # Target DOM ID in the view
"<div>#{ERB::Util.html_escape(line.chomp)}</div>".html_safe
)
end
end
rescue => e
response.stream.write turbo_stream.append(
"output",
"<div class='error'>Error: #{ERB::Util.html_escape(e.message)}</div>".html_safe
)
ensure
# Close the stream
response.stream.close
end
end
end