Search code examples
ruby-on-railsruby-on-rails-4pdfprawn

Rails render multiple pdf files to a folder


I have a controller action that renders a pdf for download. I want to render multiple pdfs to a tmp folder ( then zip them for download )

I can generate the pdfs and present to the user but I can't figure out how to create a folder to store them in.

I'm using prawn. It has the render_file method to save it to the filesystem but I don't know what directory it is or if other users could save their pdf's to the same folder, so I need to create a uniques folder for each user then save the pdf's there.

How can I do this?

my controller action is currently

def showpdf
    respond_to do |format|
      format.html
      format.pdf do
        @items.each do |pdf|
          pdf = Prawn::Document.new(page_size:  "A4",margin: [0,0,0,0])

         # pdf creation stuff...

          # this was used previously to render one pdf to the browser
          # but I need to save multiple pdf's
          #send_data pdf.render, filename: 'report.pdf', type: 'application/pdf'
        end
      end
    end

Solution

  • You will need to store all files into tmp/your-folder folder, something like this

    require 'prawn'
    @items.each do |item|
       pdf = Prawn::Document.new
       pdf.text("Lets Zip All.")
       pdf.render_file('tmp/your-folder/#{item.id}.pdf')
    end
    

    and then simply use https://github.com/rubyzip/rubyzip to zip the your-folder.

    require 'zip'
    folder = "tmp/your-folder/"
    zipfile_name = "tmp/archive.zip"
    
    input_filenames = Dir.entries("tmp/your-folder/").select {|f| !File.directory? f} 
    
    Zip::File.open(zipfile_name, Zip::File::CREATE) do |zipfile|
      input_filenames.each do |filename|
      zipfile.add(filename, folder + '/' + filename)
    end
    
    zipfile.get_output_stream("myFile") { |os| os.write "myFile contains just this" }
    end
    

    Simply send the file to user. But if the PDF contains a lot of data move them to delayed jobs. Hope this makes sense but if not please hit reply.