Create a PDF with Prawn

Prawn is a pdf generator built in ruby, that is pretty full featured.  However, I found it pretty hard to find good current documentation on using it in Rails.  Much of it was years old, and referred to older versions of prawn and older versions of Rails.  Ryan Bates’ RailsCast #153 was very helpful though, as usual.

Fortunately, there is a gem we can use:

gem 'prawn'

And of course run bundle install

Next we need to make sure Rails can accept pdfs. Your app may already have this, but if not, add this to your config/initializers/mime_types.rb file:

Mime::Type.register "application/pdf", :pdf

Now in our controller, inside the function for the view where you want to show the pdf, we need to add code for format.pdf. If you use the scaffold generator, you can see similar code to this generated automatically in the create, update, and destroy methods.

respond_to do |format|
    format.html
    format.pdf do
      pdf = Prawn::Document.new
      pdf.text "this is a pdf"
      send_data pdf.render_file
    end
  end

So we add the respond_to block, and we need the format.html line to ensure the normal html view still gets loaded. The format.pdf block will be run when we load the .pdf extension of the url address in the browser. For example, if your show view is localhost:3000/users/1, then if you now load localhost:3000/users/1.pdf, it should load the sample pdf we created. The pdf = Prawn::Document.new instantiates a new pdf using Prawn, and the pdf.render_file line actually creates the file. Now you’ll probably notice if you run this that the pdf will download. That’s because the send_data default is to download. If we pass the option disposition: inline then it will show in the browser rather than download. As shown below:

send_data pdf.render, filename: "mypdf.pdf",
                      type: "application/pdf",
  	              disposition: "inline"

We can also pass in several options when we create the pdf

img = "#{Rails.root}/app/assets/images/my_image.jpg"
pdf = Prawn::Document.new(background: img, :page_size => "LETTER", :page_layout => :landscape)

Here I create a background image for the pdf, and pass in the page size and make the layout landscape. A good resource for all the options is the Prawn resource manual. Now in my case I wanted to save the file into the database, rather than just displaying it in the browser.  So in my User model I created a column called certificate, and this is how I save the pdf to that column in the database. First I setup the paperclip gem to handle attached files. To do this, add gem ‘paperclip’ in your gem file, run bundle install, then run a migration from the command line adding the column for the attached file to the database, in my case

rails generate paperclip user certificate

and add this in the model where you want the attachment:

has_attached_file :certificate
validates_attachment_content_type :certificate, :content_type => "application/pdf"

Now that paperclip is setup, back to Prawn.  I want set a custom path to where to save the pdf. I created a path in my app to store pdfs: /app/pdfs and run this line to save the file there:

pdf.render_file File.join(Rails.root, "app/pdfs", "x.pdf")

Now that its saved in my app, I can save it to the database,

current_user.certificate = File.open("#{Rails.root}/app/pdfs/x.pdf")
current_user.save!

Now I can access the file in the view if I want

<iframe class="center" src="<%= current_user.certificate %>" width="300" height="150"> width="750" height="580"style="border: none;"> 

In summary, here’s the full code I use in the controller. Note that since I’m saving the file rather than displaying it directly in the browser, I don’t need the format.pdf block anymore.

img = "#{Rails.root}/app/assets/images/certificate.jpg"
pdf = Prawn::Document.new(background: img, :page_size => "LETTER", :page_layout => :landscape)
pdf.font "Helvetica", style: :bold
pdf.font_size 34
pdf.draw_text current_user.name, at: [300, 380]
pdf.draw_text Date.today.strftime("%A %B %e %Y "), at: [135, 55]
pdf.render_file File.join(Rails.root, "app/pdfs", "x.pdf")
current_user.certificate = File.open("#{Rails.root}/app/pdfs/x.pdf")
current_user.save!

I have another post about using strftime to format Dates in Ruby, and one about fonts that you can use with Prawn. Other helpful resources I found were:

StackOverflow questionStack Overflow question 2, SO question 3, and this Sitepoint post,

There is also a cool prawn-rails gem that is convenient, although note that in the Gemfile you need to put prawn_rails with an underscore, not a dash. Here’s a demo site with examples of this gem.

Save PDF to User Model in Ruby on Rails Using Paperclip and Prawn

I’m using paperclip and prawn to create pdf certificates for users and save them to the user model in the background.

Paperclip is often used for user uploaded files, such as images, so I was uncertain how to save the pdf that was created with prawn to the user model, since the user did not upload it themselves.  Actually turns out its pretty simple.

Once the pdf is created with Prawn (which I’ll write another post about), we simply use this code to save it to User.certificate in the database.

current_user.certificate = File.open("#{Rails.root}/app/pdfs/x.pdf")
current_user.save!

So the trick here is to call File.open and pass in the path to the pdf that I created in the background. Then simply save it to the user’s certificate.  The exclamation point is used on the save command to indicate that the command alters the object that its called on.  The exclamation point is often called a ‘bang’ in Ruby.

Credit here and here.

What Fonts are available in Prawn PDF for Rails?

I use prawn (both the prawn gem and prawn_rails gem by Whoops– note it’s an underscore, not a dash) to create pdf’s in my rails app.  You can customize the font to some extent, but here is a list of the available fonts by default that you can use in your prawn pdf:


Courier Helvetica Times-Roman Symbol ZapfDingbats
Courier-Bold Courier-Oblique Courier-BoldOblique
Times-Bold Times-Italic Times-BoldItalic
Helvetica-Bold Helvetica-Oblique Helvetica-BoldOblique

It appears that this is because these are the standard fonts that all pdf readers should be able to read.  I think it’s possible to use other fonts with prawn, but I haven’t yet figured out how to install them. If you know how, let me know in the comments!

Credit here.