On a recent project I was generating a PDF using Prawn and feeding it out to the user via send_data.  Then requirements changed (of course), and we needed to show past invoices.  To improve response times I was asked to save the generated PDFs as they wouldn’t change and the storage of them is not an issue.

Unfortunately Prawn doesn’t seem to support this functionality on it’s own, and there weren’t too many guides for how to do this out there.

Fortunately, it turned out to be pretty easy to implement.  I set up a static method in my Invoices class that takes in teh desired file name, and the list of invoices:


def self.create_pdf(invoices, filename)
   pdf = Prawn::Document.new
   eval(Invoice.get_pdf_markup(invoices))
   pdf.render_file(filename)

 end

And another static method to get the PDF markup.  Mine’s pretty long and complicated since it’s a formatted invoice.  Just put what would normally be in your prawn.pdf file here.


 def self.get_pdf_markup(invoices)
 return <<-EOS
 if invoices.blank?
 pdf.text "There has been no account activity this month"
 else
 point = [pdf.bounds.right-50, pdf.bounds.bottom + 648]
 page_counter = pdf.lazy_bounding_box(point, :width => 10) do
 pdf.text pdf.page_count, :size => 9, :align => :right
 end

 pdf.header [pdf.margin_box.top_left] do
 pdf.fill_color "299f6f"
 pdf.text "STATEMENT", :align => :center, :size => 9

 pdf.bounding_box [300,670], :width=>100 do
 pdf.text "Customer No:", :size => 9
 pdf.text "Date: ", :size => 9
 pdf.text "Page: ", :size => 9
 end

 pdf.bounding_box [400, 670], :width=> 100 do
 pdf.fill_color "000000"
 pdf.text invoices.first.invoice.accpac_customer.IDCUST.strip, :align => :right, :size => 9
 pdf.text Date.today.strftime("%m/%d/%Y"), :align => :right, :size => 9
 end

 logo_header = "#{RAILS_ROOT}/public/images/logo.png"
 pdf.image logo_header, :width => 225, :at => [5, 680]

 pdf.bounding_box [50,600], :width => 200 do
 pdf.fill_color "299f6f"
 pdf.text "Sold To:", :size => 9
 pdf.bounding_box [10, 0], :width => 190 do
 pdf.fill_color "000000"
 pdf.text invoices.first.invoice.accpac_customer.display_address.split("
")* "\n", :size => 9
 pdf.text invoices.first.invoice.accpac_customer.TEXTPHON1, :size => 9
 end
 end

 pdf.bounding_box [300,600], :width => 200 do
 pdf.fill_color "299f6f"
 pdf.text "Remit To Address:", :size => 9

 pdf.bounding_box [10, 0], :width => 190 do
 pdf.fill_color "000000"
 pdf.text REMIT_TO_ADDRESS * "\n", :size => 9
 end
 end
 page_counter.draw
 end

 data = invoices.collect{|arobl| [arobl.IDINVC, Date.strptime(arobl.DATEINVC.to_s, '%Y%m%d').strftime('%Y/%m/%d'),
 arobl.TRXTYPETXT, "", Date.strptime(arobl.DATEDUE.to_s, '%Y%m%d').strftime('%Y/%m/%d'), sprintf("%0.2f", arobl.AMTDUETC) ]}
 pdf.fill_color "000000"
 pdf.bounding_box [0,500], :width => 500 do
 pdf.table data,
 :position => :center,
 :header_text_color => "299f6f",
 :border_color => "299f6f",
 :headers => ["Document No.", "Doc. Date", "Ty.", "Reference/Applied No.", "Due Date", "Amount" ],
 :font_size => 9,
 :width => 500,
 :vertical_padding => 1
 end

 end
 EOS
 end

And to return that from your controller all you have to do is a send_data (or send_file, I opted for send_data) call with the file:


 send_data(File.read(filename), :type => "application/pdf",
 :filename => "#{Date::MONTHNAMES[params[:month]]}#{params[:year]}.pdf")




Categories

Archives

Follow

Get every new post delivered to your Inbox.