In a recent post, I talked about how to generate PDF reports in Rails using Prawn. This approach is great for generating PDF’s with lots of data tables and other variable-length content. But an alternative situation is when you already have a template authored in an application such as Adobe Acrobat and you want to populate it with data from your database. This makes it more difficult to insert variable-length content, but on the plus side, you no longer need to worry about the layout of the document.
While there are a number of libraries out there that can perform PDF manipulation, the one I have found to work best is PDFtk. There is a GUI version, but you’ll want the command line version, which is available in most package managers. 1 This library is free for personal use, but requires a license if used in production.
PDFtk is a non-ruby command line tool and while it works great on its own in that context, it will be much easier if we use a ruby wrapper, so go ahead and add the pdf-forms gem to your project.
For this example, I’ve provided a really simple PDF form that I created in Adobe Acrobat 2. You can download it here and add it to your project (I put mine in lib/pdf_templates). There are plenty of other resources out there on creating PDF forms, so I won’t go over that, but make sure you take note of the names of the fields. If you are starting with a template created by someone else, you’ll still want to open it up in Adobe Acrobat (or a similar app) to reference the names of the form fields. 3. The pdf-forms gem has a command for viewing the names, but I found that it didn’t always work.

Next, let’s get to the coding. Just as in my post on generating pdfs with Prawn, I like to represent each pdf document as a ruby class. But first let’s create a base class that takes care of the common functionality. So create a file called fillablepdfform.rb. In my rails app, I placed it in app/pdfs. 4. Here’s how my base class turned out:
class FillablePdfForm
  attr_writer :template_path
  attr_reader :attributes
  def initialize
    fill_out
  end
  def export(output_file_path=nil)
    output_path = output_file_path || "#{Rails.root}/tmp/pdfs/#{SecureRandom.uuid}.pdf" # make sure tmp/pdfs exists
    pdftk.fill_form template_path, output_path, attributes
    output_path
  end
  def get_field_names 
    pdftk.get_field_names template_path
  end
  def template_path
    @template_path ||= "#{Rails.root}/lib/pdf_templates/#{self.class.name.gsub('Pdf', '').underscore}.pdf" # makes assumption about template file path unless otherwise specified
  end
  protected
  def attributes
    @attributes ||= {}
  end
  def fill(key, value)
    attributes[key.to_s] = value
  end
  def pdftk
    @pdftk ||= PdfForms.new(ENV['PDFTK_PATH'] || '/usr/local/bin/pdftk') # On my Mac, the location of pdftk was different than on my linux server.
  end
  def fill_out
    raise 'Must be overridden by child class'
  end
end
And now I can keep my actual test pdf form class short and sweet. The fill_out method is all that’s required.
class TestPdfForm < FillablePdfForm
  def initialize(user)
    @user = user
    super()
  end
  protected
  def fill_out
    fill :date, Date.today.to_s
    [:first_name, :last_name, :address, :address_2, :city, :state, :zip_code].each do |field|
      fill field, @user.send(field)
    end
    fill :age, case @user.age
      when nil then nil
      when 0..17 then '0_17'
      when 18..34 then '18_34'
      when 35..54 then '35_54'
      else '55_plus'
    end
    fill :comments, "Hello, World"
  end
end
And my controller might look something like this:
class UsersController < ApplicationController
  def show
    user = User.find(params[:id])
    respond_to do |format|
      format.pdf { send_file TestPdfForm.new(user).export, type: 'application/pdf' }
    end
  end
end
And that’s all you need! The generated form will be both readable and writable in Adobe Reader and Mac Preview. So if you need the user to fill out a few additional fields, they can do so. But if you don’t want this, simply mark the fields in your template as read-only. So if your template isn’t a “form” but you just want to merge some data into a document, this is still a great way to do it.
From there, creating additional forms is extremely easy. The only difficulty I ever encounter is in figuring out the proper field names for templates I didn’t create, but this is still fairly trivial.
If you have any questions, send them to me on Twitter.
-  While PDFtk is free for personal use, it does require a license in production. ↩ 
-  There are many lower-cost and free alternatives to Adobe Acrobat, but I don’t have any experience with them, so I won’t make any recommendations. ↩ 
-  If Acrobat shows you an error message that something like “This form cannot be edited in Acrobat. Please use Adobe LiveCycle Designer to edit this form”, then you’ll either need to either get a version of the PDF that doesn’t have these permissions turned on or you’ll need to export it the document as a new pdf, and then re-import it into Acrobat and lay out the form fields yourself. ↩ 
-  You may need to restart your dev server to make sure it picks up changes in this new folder. ↩ 
