Jaeger
Jaeger

Reputation: 1754

"cannot open entry for reading while its open for writing" while creating a zip file

I'm trying to create a function that would download a zip that contains files. I followed this tutorial, that says that my code should look like the following if you want to download a CSV (I translated the comments) :

def exporter_zip
    # CSV's header
    csv = "Title;Content;Publishing date;File name;\n" 
    # Loop over articles saved in database
    Article.all.each do |article|
      # Creating the CSV with datas
      csv += "#{article.title};#{article.content};#{article.publishing_date.strftime("%Y-%m-%d") if article.publishing_date };#{article.file_name}\n"
    end

    # Creating the zip file inside the folder
    zip_tmp = File.new("#{Rails.root}/db/mon_fichier.zip",  "w+")

    # opening the file in writing mode
    Zip::File.open(zip_tmp.path, Zip::File::CREATE) {
      |zipfile|

     # Inserting the csv variable's content inside the article.csv file, which is inserted into the zip file

      zipfile.get_output_stream("articles.csv") { |f| f.puts csv }
    }

    # Sending the created file
    send_file "#{Rails.root}/db/mon_fichier.zip"
  end

Here is how i adapted the code:

class DownloadController < ApplicationController
  require 'zip'

  def zip
    # Creating zip file
    zip_tmp = File.new("#{Rails.root}/public/zip-#{Time.now.strftime('%d-%m-%Y')}.zip", 'w+')
    FileDetail.all.each do |fichier|
      Zip::File.open(zip_tmp.path, Zip::File::CREATE) { |zipfile|
        # fichier.filename => file.mp3
        # fichier.path => path/to/file.mp3
        zipfile.get_output_stream(fichier.filename, fichier.path)
      }
    end

    send_file "#{Rails.root}/public/zip-#{Date.today.to_time}.zip"
  end
end

However, while I'm not even sure I'm doing this correctly, I get the following error: cannot open entry for reading while its open for writing, targetting the following line: Zip::File.open(zip_tmp.path, Zip::File::CREATE) { |zipfile|

Can anyone can tell me what's going on? I never did this before so I don't know what went wrong..

Thank you in advance

Upvotes: 0

Views: 281

Answers (1)

Jem
Jem

Reputation: 656

FileDetail.all.each do |fichier|
  Zip::File.open(zip_tmp.path, Zip::File::CREATE) { |zipfile|
    # fichier.filename => file.mp3
    # fichier.path => path/to/file.mp3
    zipfile.get_output_stream(fichier.filename, fichier.path)
  }
end

Doing it this way will attempt to create the zip file for each member of your FileDetail. You should code it to only open and create once:

Zip::File.open(zip_tmp.path, Zip::File::CREATE) do |zipfile|
  FileDetail.all.each do |fichier|
    # fichier.filename => file.mp3
    # fichier.path => path/to/file.mp3
    zipfile.get_output_stream(fichier.filename, fichier.path)
  end
end

Upvotes: 1

Related Questions