Versione breve
https://github.com/fringd/zipline
Long Version
così la risposta di jo5h non ha funzionato per me in rotaie 3.1.1
ho trovato un video di youtube che ha aiutato, però.
http://www.youtube.com/watch?v=K0XvnspdPsc
il nocciolo sta creando un oggetto che risponde ad ogni ... questo è quello che ho fatto:
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:
soluzione sopra non ha effettivamente lavoro ... il problema è che rubyzip ha bisogno di saltare il file per riscrivere le intestazioni per le voci come va. in particolare ha bisogno di scrivere la dimensione compressa PRIMA che scriva i dati. questo non è possibile in una vera situazione di streaming ... quindi alla fine questo compito potrebbe essere impossibile. c'è la possibilità che possa essere possibile bufferizzare un intero file alla volta, ma questo sembrava meno ne valeva la pena. alla fine ho appena scritto un file tmp ... su heroku posso scrivere su Rails.root/tmp meno feedback istantanei, e non ideale, ma necessario.
ALTRO EDIT:
ho avuto un'altra idea di recente ... potremmo conoscere la dimensione compressa dei file, se non li impacco. il piano più o meno così:
sottoclasse della classe ZipStreamOutput come segue:
- utilizzare sempre il metodo di compressione "memorizzato", in altre parole non comprimere
- assicurare che non abbiamo mai chiedere indietro per modificare il file intestazioni, ottenere tutto fino davanti
- riscrivere qualsiasi codice relativo al sommario che cerca
non ho cercato di attuare questo ancora, ma sarà riferire se ci è un successo.
OK ONE Ultima modifica:
Nello standard zip: http://en.wikipedia.org/wiki/Zip_(file_format)#File_headers
accennano che c'è un po 'si può capovolgere di mettere la dimensione, la dimensione compressa e crc dopo che un file. così il mio nuovo piano era quello di creare una sottoclasse zipoutput flusso in modo che
- set di questo flag
- scrive dimensioni e CRC dopo i dati
- mai riavvolge uscita
, inoltre, avevo bisogno di ottenere tutte le hack per lo streaming di output su binari riparati ...
comunque ha funzionato!
ecco un gioiello!
https://github.com/fringd/zipline
ZipOutputStream non può farlo perché cerca avanti e indietro attraverso lo stream mentre scrive i dati compressi (vedere 'ZipOutputStream # update_local_headers', chiamato da' ZipOutputStream # close'). Pertanto, è impossibile fornire blocchi di dati con ZipOutputStream prima che l'operazione venga completata. –