Prawn Thumb

Create a PDF invoice using Prawn in Rails

Rails

After coming to the realization that I was going to need to create PDFs on the fly for the rails application I’m working on for a client, I started my hunt for something that could get the job done quick with minimal effort. I’m in no way a full-time rails developer yet, but I’m slowly working on getting out of the amateurs and Prawn gem was highly recommended by other rails enthusiasts.

Perhaps the greatest gripe I had about Prawn on first encounter was the lack of being able to use CSS & HTML for easy styling, which is something I’m much more comfortable with from experience. But after realizing that there weren’t many candidates that allowed this type of styling format in PDFs, I decided to give Prawn a go anyhow.

I also found prawnto googling, which is a plugin used with Prawn to provide easy access to the prawn library and allows for a simple respond_to block slapped into your controller to provide you with the .pdf extension. This seemed perfect for what I needed so I figured I’d share my knowledge with others so lets get started.

Let’s create a rails customer project

# Create a rails project
rails customer

# Change directories to our project
cd customer

Let’s do some scaffolding to save some time. In this case we are going to create invoices for our customers.

# Scaffold an invoice for our customer
script/generate scaffold invoice customer_name:string item_name:string item_price:string item_qty:integer

# Migrate your database
rake db:migrate

Launch your server:

script/server

Time to create a new customer invoice that we can work with. Go to your http://localhost:3000/invoices page and click on new invoice and add some data; here is what I used:

Name: Branden Silva
Item Name: Awesome Serif Fonts
Item Price: 24.99
Item Quantity: 2

Once done, http://localhost:3000/invoice/1 should now be your first customer invoice. Awesome, now lets get prawn & prawnto installed.

Getting prawn & prawnto up and running

I’m using rails 2.3.5 for reference so your results may vary depending on what version you are running. First you’ll want to download the prawn gem and prawnto plugin into your project like so:

 # Install Prawn Gem
sudo gem install prawn

# Install Prawnto Plugin
script/plugin install git://github.com/thorny-sun/prawnto.git

Note: If you end up getting a “uninitialized constant Mime::PDF” error further down the tutorial when launching the pdf then prawnto may have not installed correctly. I recommend you go download prawnto at the git repository here and create a folder prawnto under your vendor/plugins directory in your rails application and stash the files in there.

Then your going to want to add prawn to your environment.rb file to avoid any dependency issues in the future:

# Add this line to your config/environment.rb file.
config.gem "prawn"

Then you are going to have to set up prawnto in your invoice controller. Here I’m going to fetch a customer invoice and display a pdf in my show action when a user adds a .pdf extension to the url. The part you’ll want to pay attention to and add is the format.pdf line.

 # invoices/show
def show
@invoice = Invoice.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml  { render :xml => @invoice }
format.pdf { render :layout => false } # Add this line
end
end

Now your going to need to create a file to put your prawn code into. In this case I just create a blank show.pdf.prawn file under the http://localhost:3000/views/invoices folder.

Now it’s time to start dishing some prawn

Lets start writing some prawn code. You can access your PDF at any time by simply adding a .pdf extension to your individual customer invoices. So http://localhost:3000/invoices/1 is how you show your customer invoice information via the browser and http://localhost:3000/invoices/1.pdf would be how you access your customer invoice via PDF format. Of course it’s not going to do anything until we write some code so open up your show.pdf.prawn file.

I usually start off by adding an image to my pdfs to give them a nice spiffy look. Here is the awesome logo I’m going to use:

Awesome Company

Now save your logo (or mine) to your public/images directory in your rails app. This way you can reference it in your show.pdf.prawn file. Here is what the code looks like in our show.pdf.prawn file to add this image:

# Assign the path to your file name first to a local variable.
logopath = "#{RAILS_ROOT}/public/images/awesomecompany.jpg"

# Displays the image in your PDF. Dimensions are optional.
pdf.image logopath, :width => 197, :height => 91

We are simply creating a local variable called logopath and then displaying it with the pdf.image method off our pdf object. I’ve also set the width and height of the image here.

How about we add some text now to our PDF. First lets shift the page down 70 points, add some styling, and then we can access our lovely instance variables that come with our rails app to pull in dynamic data.

pdf.move_down 70

# Add the font style and size
pdf.font "Helvetica"
pdf.font_size 18
pdf.text_box "Invoice # #{@invoice.id}", :align => :right

pdf.font_size 22
pdf.text "Thank you for your order, #{@invoice.customer_name}.", :align => :center
pdf.move_down 20

pdf.font_size 14
pdf.text "Below you can find your order details. We hope you shop with Awesome Company again in the future. Now unleash those fonts like hell have no fury!", :align=> :center

Thats a big chuck of code so let me break it down for you. pdf.move_down shifts your cursor focus down the PDF document. This doesn’t apply to our pdf.text_box which is entirely different creature that doesn’t follow the normal pdf page flow (you can think of text_boxes like absolute divs in html). pdf.font allows you to use supported prawn fonts. I’m sure it can be extended but I haven’t researched it in depth because Helvetica fits my needs for this example and client project. pdf.font_size adjusts the size of your text.

So what would we you do if you needed a table? Simple enough, try this:

invoiceinfo = [["Item Name", "#{@invoice.item_name}"], ["Item Price", "#{@invoice.item_price}"],["Item Quantity", "#{@invoice.item_qty}"]]

pdf.move_down 30

pdf.table invoiceinfo,
:border_style => :grid,
:font_size => 11,
:position => :center,
:column_widths => { 0 => 150, 1 => 250},
:align => { 0 => :right, 1 => :left, 2 => :right, 3 => :left},
:row_colors => ["d2e3ed", "FFFFFF"]

Here we are creating a multi-dimensional array and assigning it values from our rails application. In this case our local variable invoiceinfo is storing our table information. You don’t have to put the information in it’s own variable but I find its easier to keep the data separate from the formatting of the table. #{@invoice.item_name} would pull our item name from our rails application and display it in our pdf, yeah, it’s that easy. pdf.table calls invoiceinfo and then assigns a few attributes to that table. Pretty awesome that it’s that clean and simple to style everything up with a few key value pairs. I’ve even added some row colors to make it easier to scan for the user.

However, a PDF wouldn’t be complete without allowing page numbers. Fairly straightforward to do in prawn as well, here is the code:

pdf.font_size 14

pdf.bounding_box([pdf.bounds.right - 50,pdf.bounds.bottom], :width => 60, :height => 20) do
pagecount = pdf.page_count
pdf.text "Page #{pagecount}"
end

Here we shrink the pdf.font_size down so the page number won’t be enormous. We start to get into the pdf.bounding_box creature. You can basically define boxes inside your pdf. In this case we are telling the bounding_box to find the right most edge (bounds) of the box you are in, which happens to be the pdf document, then we subtract 50 points. We do the same thing with the bottom minus the shift of 50 points. We then slap a width and height to our bounding box and perform a block of code in the bounding_box. the local variable pagecount is assigned and then displayed with pdf.text.

Heres my final example for download.

Well there you have it; a simple invoice with very little effort. With some additional research you can add more data and style it further to fit your needs. Before you go though lets add a nice link to our PDF on our main show page so the customer can find it without having to type it in the URL manually. Head over to your views folder and open your http://localhost:3000/invoices/show.html.erb file. Then you’ll want to add this code somewhere in your file:

<%= link_to "PDF Invoice", invoice_path(@invoice, :format => 'pdf')%>

We’re basically just calling the invoices path and throwing it the invoice with an extension of pdf attached to the end of it. This should show up as a link now so when your customer clicks on it they will be redirected to the PDF version of your data in your rails application.

Conclusion

Prawn is definitely a simple and easy way to get PDFs up and going with very minimal effort. The only downsides I’ve noticed from my perspective is it’s not completely possible to style ever nook and cranny because your at the whims of Prawns formatting options; but I’m guessing it won’t make much of a difference because there aren’t to many alternatives as nice as Prawn or that have this simple functionality. Documentation was available, but examples were limited but nothing a Google search can’t net you. Hopefully this helps out some of those in pursuit of a quick PDF solution.

Final Note:prawnto’s website mentions it only been updated to rails 2.2 but I had no problems getting it to work on 2.3.5. It may however be broken in rails 3 so just be aware of that when upgrading.

Other Resources

Friends who care are friends that share :)

Branden Silva is a creative cookie who likes to devour the internet in a big way. When he's not building amazing web/mobile sites and applications for clients, he's building his own frankenstein creations with the latest and greatest web standards. He's pretty active on twitter and likes to meet new designer and coders to collaborate with on fun projects.

8 Comments (RSS)

  • untaldouglas wrote:

    Thanks !

    Well written, nice work; I appreciate your time for sharing.

    Reply

    • Branden Silva wrote:

      Thanks for the response untaldouglas. It is always nice to know others find some usefulness out of these tutorials.

  • Wordpress Themes wrote:

    Nice brief and this post helped me alot in my college assignement. Thanks you seeking your information.

    Reply

    • Branden Silva wrote:

      Sure thing :) Thanks for the visit. Good luck with your college work!

  • gangadhar wrote:

    we are not able get the page in pdf format.iam getting the page in html file. if i delete the show.erb,it is asking for show.erb like template is missing

    Reply

    • Branden Silva wrote:

      Hi,

      you need to make sure that you setup prawnto and install it correctly.

  • mia wrote:

    i cant rails plugin install git://github.com/thorny-sun/prawnto.git
    i got fatal error, which the repo is empty..
    i just can gem install prawn..
    could u guys help me? please

    Reply

  • mia wrote:

    i got did, succesfully install prawnto in
    github.com/prior/prawnto.git
    but i facing error whereby i cant start server(rails s)

    /home/railshero/customer/config/environment.rb:6:in `’: undefined local variable or method `config’ for main:Object (NameError)

    Reply

Leave a Comment