2

I generate a PDF file for an invoice in a background job and I want to attach it to the invoice. I use Carrierwave for file uploads but here I do not upload it from the UI. I would like to be able to attach the file without saving it on disk.

invoice.rb

mount_uploader :file, InvoiceFileUploader

background job

class GeneratePdfJob < ApplicationJob
  queue_as :default

  def perform(invoice)
    pdf = InvoiceServices::PdfGenerator.new(invoice)
    file_name = [invoice.number.gsub('/','-'), invoice.due_date.to_s, SecureRandom.urlsafe_base64].join('-') + '.pdf'
    pdf.render_file(file_name)
    file = File.new(file_name)
    invoice.file = file
    File.delete(file_name)
  end
end

So right now I call render_file method to actually create the file but this file gets saved in the root folder of my application so I need to delete it afterwards. Is there a better way? Is there a way to attach the file without actually saving it on disk?

jedi
  • 2,003
  • 5
  • 28
  • 66

1 Answers1

6

what you are trying to archive is really impressive. Thanks for the idea. this will reduce lots of disk IO-related issues in PDF generation.

1st: Renders the PDF document to a string

instead of render_file method use Prawn::Document#rendermethod which returns string representation of the PDF.

2nd: use that string to upload to carrier wave without any tempory file.

# define class that extends IO with methods that are required by carrierwave
class CarrierStringIO < StringIO
  def original_filename
    "invoice.pdf"
  end

  def content_type
    "application/pdf"
  end
end

class InvoiceFileUploader < CarrierWave::Uploader::Base
  def filename
    [model.number.gsub('/','-'), model.due_date.to_s, SecureRandom.urlsafe_base64].join('-') + '.pdf'
  end
end

class Invoice
  mount_uploader :file, InvoiceFileUploader

  def pdf_data=(data)
    self.file = CarrierStringIO.new(data)
  end
end

class GeneratePdfJob < ApplicationJob
  queue_as :default

  def perform(invoice)
    pdf = InvoiceServices::PdfGenerator.new(invoice)        
    invoice.pdf_data = pdf.render
  end
end
Oshan Wisumperuma
  • 1,808
  • 1
  • 18
  • 32