Назначьте response_body
объект, который отвечает на #each
:
class Streamer
def each
10_000_000.times do |i|
yield "This is line #{i}\n"
end
end
end
self.response_body = Streamer.new
Если вы используете 1.9.x или Backports gem, вы можете написать это более компактноиспользование Enumerator.new
:
self.response_body = Enumerator.new do |y|
10_000_000.times do |i|
y << "This is line #{i}\n"
end
end
Обратите внимание, что когда и если данные сбрасываются, зависит от используемого обработчика Rack и используемого сервера.Я подтвердил, что Mongrel, например, будет передавать данные в потоковом режиме, но другие пользователи сообщали, что, например, WEBrick буферизует их до тех пор, пока ответ не будет закрыт.Нет способа заставить ответ сбросить.
В Rails 3.0.x есть несколько дополнительных ошибок:
- В режиме разработки, например, доступ к классам модели извнутри перечисления могут возникнуть проблемы из-за плохого взаимодействия с перезагрузкой класса.Это открытая ошибка в Rails 3.0.x.
Ошибка во взаимодействии между Rack и Rails приводит к тому, что #each
вызывается дважды для каждого запроса.Это еще один открытый баг .Вы можете обойти это с помощью следующего патча обезьяны:
class Rack::Response
def close
@body.close if @body.respond_to?(:close)
end
end
Обе проблемы исправлены в Rails 3.1, где потоковая передача по HTTP является функцией выделения.
Обратите внимание, чтоДругое распространенное предложение, self.response_body = proc {|response, output| ...}
, работает в Rails 3.0.x, но устарело (и больше не будет передавать данные) в версии 3.1.Назначение объекта, отвечающего #each
, работает во всех версиях Rails 3.