versión corta
https://github.com/fringd/zipline
Versión larga
así la respuesta de jo5h no funcionó para mí en los carriles 3.1.1
Encontré un video de youtube que ayudó, sin embargo.
http://www.youtube.com/watch?v=K0XvnspdPsc
el quid de la cuestión es la creación de un objeto que responde a cada ... esto es lo que hice:
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
EDIT:
la solución anterior en realidad no trabajo ... el problema es que rubyzip necesita saltar el archivo para volver a escribir los encabezados para las entradas a medida que avanza. particularmente necesita escribir el tamaño comprimido ANTES de escribir los datos. esto simplemente no es posible en una situación de transmisión real ... por lo que, en última instancia, esta tarea puede ser imposible. existe la posibilidad de que sea posible almacenar en búfer un archivo completo a la vez, pero esto parecía menos valioso. en última instancia, acabo de escribir en un archivo tmp ... en heroku puedo escribir en Rails.root/tmp menos comentarios instantáneos, y no es ideal, pero sí es necesario.
otra edición:
tengo otra idea recientemente ... podríamos saber el tamaño comprimido de los archivos si no comprimirlos. el plan es algo como esto:
subclase de la clase ZipStreamOutput de la siguiente manera:
- siempre utilice el método de compresión "almacenado", en otras palabras, no comprima
- garantizar que nunca buscar hacia atrás para cambiar el archivo cabeceras, lo entiendo bien por adelantado
- reescribir cualquier código relacionado con TOC que busca
no he tratado de implementar esto todavía, pero informaré si hay es cualquier éxito.
OK UNO Última edición:
En el estándar postal: http://en.wikipedia.org/wiki/Zip_(file_format)#File_headers
mencionan que hay un poco se puede dar la vuelta a poner el tamaño, el tamaño comprimido y CRC vez que un archivo. por lo que mi nuevo plan era subclase zipoutput corriente de modo que
- pone esta marca indicadora
- escribe tamaños y CRC después de los datos
- nunca se rebobina salida
, además, que necesitaba para obtener toda la hacks para transmitir la salida en rieles fijos ...
de todos modos funcionó!
aquí hay una joya!
https://github.com/fringd/zipline
ZipOutputStream no puede hacer eso porque busca hacia adelante y hacia atrás a través de la secuencia mientras escribe los datos comprimidos (consulte 'ZipOutputStream # update_local_headers', llamado desde' ZipOutputStream # close'). Por lo tanto, es imposible servir trozos de datos con ZipOutputStream antes de que la operación se complete. –