Using Prawn on Heroku
Asked Answered
D

2

10

We are currently working on a Rails application hosted on Heroku. We are trying to generate a PDF and push it to the user to download.

We are using Prawn to handle the PDF generation.

Our code for generating the PDF is currently:

Prawn::Document.generate @name[0]+ ".pdf" do

Followed by all of our code to generate the document. Unfortunately, this saves the document to the disk which is not possible (to the best of my knowledge) for applications hosted on Heroku.

We then push it to the user using

send_file "#{Rails.root}/"+@name[0]+ ".pdf", :type =>
'application/pdf',:filename => @name[0]+ ".pdf"

Is there any way using Prawn to directly push the download of the document to the user without saving the document to disk first? If not, are there any other gems for generating PDFs that don't require saving the file to the disk prior to sending the file?

Duke answered 12/3, 2012 at 21:0 Comment(0)
B
7

On Aspen/Bamboo, you can save the file to disk in the tmp/ directory in your application directory (possibly Rails.root.join("tmp")) or any subdirectory.

On Cedar, you can save the file to disk anywhere in your application directory, but you should still choose a subdirectory of your application's tmp/ directory anyway.

In either case, saved files are ephemeral. They are not shared between two running instances of your application; they are not kept between restarts; etc. Do not rely on saving the file in one request and then being able to access it in a second request.

Brothers answered 12/3, 2012 at 21:14 Comment(1)
See the other comment about using prawn without a file name to render in memory.Falda
F
9

Though this was answered long ago, I'll post for others who may want to do this.

You can also call render with no file name in current Prawn v0.13.2. A string will be returned, which can be sent to the client with send_data. The pattern is:

pdf = Prawn::Document.new
# ... calls to build the pdf
send_data pdf.render, 
          type: 'application/pdf', 
          filename: 'download_filename.pdf',  
          disposition: :inline

This will display the PDF in the browser. If you want instead to have the user download it, omit , disposition: :inline

Of course you only want to do this if the document is reasonably short or your system is not heavily used because it will consume RAM until the user's download is complete.

Flaring answered 12/1, 2014 at 22:33 Comment(3)
I guess one challenge might be the 30 second request limit imposed by Heroku. If the file processing takes longer than 30 second - there's a chance the application would fail with 500.Tabatha
@Tabatha While that's true, the OP's original solution would have failed for this reason before this one because writing and then reading a file is slower than buffering in memory. I was just showing that it's possible to avoid the file i/o.Flaring
agree - was just commenting on your answer coz I like it :)Tabatha
B
7

On Aspen/Bamboo, you can save the file to disk in the tmp/ directory in your application directory (possibly Rails.root.join("tmp")) or any subdirectory.

On Cedar, you can save the file to disk anywhere in your application directory, but you should still choose a subdirectory of your application's tmp/ directory anyway.

In either case, saved files are ephemeral. They are not shared between two running instances of your application; they are not kept between restarts; etc. Do not rely on saving the file in one request and then being able to access it in a second request.

Brothers answered 12/3, 2012 at 21:14 Comment(1)
See the other comment about using prawn without a file name to render in memory.Falda

© 2022 - 2024 — McMap. All rights reserved.