Короткая версия
https://github.com/fringd/zipline
Длинная версия
, поэтому ответ jo5h у меня не сработал в рельсах 3.1.1
я нашелвидео на YouTube, которое помогло, однако.
http://www.youtube.com/watch?v=K0XvnspdPsc
суть в том, что он создает объект, который отвечает каждому ... вот что я сделал:
class ZipGenerator
def initialize(model)
@model = model
end
def each( &block )
output = Object.new
output.define_singleton_method :tell, Proc.new { 0 }
output.define_singleton_method :pos=, Proc.new { |x| 0 }
output.define_singleton_method :<<, Proc.new { |x| block.call(x) }
output.define_singleton_method :close, Proc.new { nil }
Zip::IoZip.open(output) do |zip|
@model.attachments.all.each do |attachment|
zip.put_next_entry "#{attachment.name}.pdf"
file = attachment.file.file.send :file
file = File.open(file) if file.is_a? String
while buffer = file.read(2048)
zip << buffer
end
end
end
sleep 10
end
end
def getzip
self.response_body = ZipGenerator.new(@model)
#this is a hack to preven middleware from buffering
headers['Last-Modified'] = Time.now.to_s
end
РЕДАКТИРОВАТЬ:
вышеупомянутое решение не работает на самом деле ... проблема в том, что rubyzip нужно перескочить по файлу, чтобы переписать заголовки для записей, как он идет.в частности, он должен записать сжатый размер, прежде чем он записывает данные.это просто невозможно в действительно потоковой ситуации ... так что в конечном итоге эта задача может оказаться невозможной.есть вероятность, что можно буферизовать целый файл за раз, но это казалось менее стоящим.в конце концов я просто написал в файл tmp ... на heroku я могу написать в Rails.root / tmp меньше мгновенной обратной связи, и не идеально, но необходимо.
ДРУГОЕ РЕДАКТИРОВАНИЕ:
я получилНедавно появилась еще одна идея ... мы МОЖЕМ знать размер сжатых файлов, если мы не сжимаем их.план выглядит примерно так:
подкласс класса ZipStreamOutput следующим образом:
- всегда использует «сохраненный» метод сжатия, другими словами, не сжимайте
- убедитесь, что мы никогда не стремимся назад изменить заголовки файлов, все получится сразу
- переписать любой код, связанный с оглавлением, который ищет
Я еще не пытался реализовать это, нобудет сообщать в случае успехаразмер, сжатый размер и crc ПОСЛЕ файла.поэтому мой новый план заключался в создании подкласса потока zipoutput, чтобы он
- устанавливал этот флаг
- записывал размеры и CRC после того, как данные
- никогда не перематывали бы вывод
Более того, мне нужно было получить все хаки для исправления потокового вывода в рельсах ...
В любом случае все это работало!
вот драгоценный камень!
https://github.com/fringd/zipline