Blog
Whilst working on client projects we often find useful bits of information out. Where possible we blog about that information to pass on our knowledge. Below are some of our most recent entries.
PDF Generation in Rails
We were recently set the challenge by Bluestorm to create a PDF plugin for their in house Rails based CMS.
Having not done PDF generation in Rails before we needed a starting point and rather than doing some random searches on Google, we put out a few tweets to get advice from developers we knew and trusted. The most common piece of advice was to use Prawn with the Rails plugin Prawnto. We now had a starting point for PDF generation side of things.
The next stage was to start prototyping the document generation side of things. The client had provided wireframes of the functionality, and these included the ability to see the PDF being built on the fly as the editors added more and more content and imagery. The simplest solution here was show the PDF as a html document within the editing page.
We started the prototype by creating a series of user stories and putting those stories into Cucumber features. Within a short space of time we had our basic document creation functionality up and running. We were still left with one problem though. The generation of the PDF document.
Prawn and Prawnto
Having had these tools recommended to us we started testing how we could take our HTML preview and turn it into a PDF document. It didn't take us long to realise that using Prawn was going to become complicated and potentially pretty unflexible as the project developed.
Some sample code for Prawn PDF generation below:
# views/orders/show.pdf.prawn
pdf.text "Order ##{@order.id}", :size => 30, :style => :bold
pdf.move_down(30)
items = @order.cart.line_items.map do |item|
[
item.product.name,
item.quantity,
number_to_currency(item.unit_price),
number_to_currency(item.full_price)
]
end
pdf.table items, :border_style => :grid,
:row_colors => ["FFFFFF","DDDDDD"],
:headers => ["Product", "Qty", "Unit Price", "Full Price"],
:align => { 0 => :left, 1 => :right, 2 => :right, 3 => :right }
pdf.move_down(10)
pdf.text "Total Price: #{number_to_currency(@order.cart.total_price)}", :size => 16,
:style => :bold
As you can see, using Prawn would mean we would need to write a parser to convert our already existing HTML preview code into relevant Prawn related calls. Whilst this wouldn't be impossible, we like to keep our code as simple as possible, so future development is easier. We were also concerned how close the final PDF document would look to the HTML preview.
We decided we needed to look for some way to convert our HTML into a PDF document without the worry of the final document not looking exactly the same as the preview.
Prince XML and Princely
Prince XML is a command line tool that converts XML and HTML into PDF documents. To make things even easier their is a Rails wrapper for the library called Princely. So now we could use our existing view code to generate the PDF documents. We just needed to update our controller and bang, we were done.
def show
respond_to do |format|
format.html
format.pdf do
render :pdf => "filename", :stylesheets => ["application", "prince"], :layout => "pdf"
end
end
end
Easy right? Well, there was one thing that stopped us dancing around the office. Prince XML requires a Server Licence which costs $3,800. This was going to blow our client's budget.
Wicked PDF and wkhtmltopdf to the rescue!
Having just given up on the idea of Prince XML we found exactly what we were looking for in Wicked PDF, a rails plugin that uses wkhtmltopdf to generate PDF documents from HTML code.
The code to generate the PDF document was again very simple.
show.wants.pdf {
render :pdf => @print_publication.title,
:template => 'admin/print_publications/show.pdf.erb',
:layout => 'pdf.pdf.erb',
:disable_javascript => false,
:margin => {:top => 20,
:bottom => 20,
:left => 20,
:right => 20},
:zoom => 2,
:disable_smart_shrinking => false,
}
(Yes we are using resource_controller).
One thing to note is that we have enabled JavaScript as part of the PDF generation. We needed to use JavaScript in the view code as wkhtmltopdf doesn't support CSS 3 columns. It does have other CSS 3 support, just not columns. As the PDF documents required a two column structure we ended up using the Columnizer jQuery Plugin to generate the columns.
In our experience it was worthwhile disabling the smart shrinking in wkhtmltopdf as this caused some problems with the generated PDF not looking exactly the same as the HTML preview.
Conclusion
We can see that Prawn is a great library and is really powerful, but wkhtmltopdf offered us the ability to use the same view code for the HTML preview to generate the PDF document. This meant that anyone with HTML experience could generate a new PDF template easily.
TweetRead more entries
Keep up to date
Want to find out more?
If we have piqued your interest then we'd love to hear from you.