Skip to content

PDFKit in Rails 3.1 on Heroku

October 14, 2011

So PDFkit is totally awesome, but there are a few gotchas to be aware of if you are on a single threaded server (`rails server`) or a read-only filesystem (Heroku).

The first thing to note is that with the introduction of the asset pipeline, assets (images, stylesheets, javascripts) are no longer served up directly but instead are first processed by your rails app and then served.  This means that in a single threaded process (`rails server` or Heroku with a single dyno) PDFs generated with an image or external stylesheet will stall and timeout.  This is because while the thread is being used to process the PDF, wkhtmltopdf sends another request to fetch the external data and we find ourselves in a deadlock as the two processes wait for each other to complete.

For stylesheets, the simplest solution I found was to have your styles placed inline and perhaps have them conditionally placed with this helpful bit of code:

def request_from_pdfkit?
  # when generating a PDF, PDFKit::Middleware will set this flag
  request.env["Rack-Middleware-PDFKit"] == "true"
end

You could also try serving a stylesheet directly from the public directory (bypassing the asset pipeline, but I have not tested this.

With images it is a little more tricky.  We still cannot use the asset pipeline for reasons already discussed.  If we give a full URL such as “http://example.com/image.png” the server hangs and times out, and if we provide a relative path to an image in the public directory PDFKit doesn’t seem to find it.  So what to do?!

It turns out that when wkhtmltopdf encounters an image tag with a relative path, it actually looks for the image at the full UNIX path.  So, we create a new image_tag helper that will give the full UNIX path to the file in question:

def pdf_image_tag(filename, options = {})
  path = Rails.root.join("app/assets/images/#{filename}")
  options[:src] = path.to_s
  attributes = options.map{ |k,v| "#{k}='#{v}'" }.join(" ")
  raw("<img #{attributes}/>")
end

There you have it. PDFKit playing nice with Heroku and Rails 3.1

Advertisements

From → Uncategorized

2 Comments
  1. Guillaume permalink

    Hi,

    Thanks for this post. Very helpful!
    I was wondering if you could help with two issues:
    1. To serve the stylesheets inline I’d need to pre-process the .scss file to convert them into a regular css files. Do you know how to do this from the controller?
    2. I don’t get how you get “pdf_image_tag” method to be called instead of the regular “image_tag”

    Hope you can help.

    Cheers,

    Guillaume

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: