Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<h1>Short Version</h1> <p><a href="https://github.com/fringd/zipline" rel="noreferrer">https://github.com/fringd/zipline</a></p> <h1>Long Version</h1> <p>so jo5h's answer didn't work for me in rails 3.1.1</p> <p>i found a youtube video that helped, though.</p> <p><a href="http://www.youtube.com/watch?v=K0XvnspdPsc" rel="noreferrer">http://www.youtube.com/watch?v=K0XvnspdPsc</a></p> <p>the crux of it is creating an object that responds to each... this is what i did:</p> <pre><code> class ZipGenerator def initialize(model) @model = model end def each( &amp;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 :&lt;&lt;, 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 &lt;&lt; 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 </code></pre> <p>EDIT:</p> <p>the above solution didn't ACTUALLY work... the problem is that rubyzip needs to jump around the file to rewrite the headers for entries as it goes. particularly it needs to write the compressed size BEFORE it writes the data. this is just not possible in a truly streaming situation... so ultimately this task may be impossible. there is a chance that it might be possible to buffer a whole file at a time, but this seemed less worth it. ultimately i just wrote to a tmp file... on heroku i can write to Rails.root/tmp less instant feedback, and not ideal, but neccessary.</p> <p>ANOTHER EDIT:</p> <p>i got another idea recently... we COULD know the compressed size of the files if we do not compress them. the plan goes something like this:</p> <p>subclass the ZipStreamOutput class as follows:</p> <ul> <li>always use the "stored" compression method, in other words do not compress</li> <li>ensure we never seek backwards to change file headers, get it all right up front</li> <li>rewrite any code related to TOC that seeks</li> </ul> <p>I haven't tried to implement this yet, but will report back if there's any success.</p> <p>OK ONE LAST EDIT:</p> <p>In the zip standard: <a href="http://en.wikipedia.org/wiki/Zip_(file_format)#File_headers" rel="noreferrer">http://en.wikipedia.org/wiki/Zip_(file_format)#File_headers</a></p> <p>they mention that there's a bit you can flip to put the size, compressed size and crc AFTER a file. so my new plan was to subclass zipoutput stream so that it</p> <ul> <li>sets this flag</li> <li>writes sizes and CRCs after the data</li> <li>never rewinds output</li> </ul> <p>furthermore i needed to get all the hacks in order to stream output in rails fixed up...</p> <p>anyways it all worked!</p> <p>here's a gem!</p> <p><a href="https://github.com/fringd/zipline" rel="noreferrer">https://github.com/fringd/zipline</a></p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload