##CREATING PDF USING PRAWN IN ROR
Recently i was working on a client project and i realized that i need to create a PDF for generating a invoice on the fly. I wanted something
As i started searching my way for options, i found out that there are lot of gems and plugins available in the rails community for generating PDF.
There were two options for me which were widely used for generating PDF.
So I chose Prawn for this project and believe me adding this to my rails application wasn’t that difficult.
- First thing that we need to do here is to add the prawn gem inside our gemfile and run the bundle command.
gem 'prawn'
- Second thing that we need to do is that we need to create a PDF Mime::Type inside config/initializers/mime_types.rb that is because we need to notify rails about the PDF mime type.
Mime::Type.register "application/pdf", :pdf(Now when there is a pdf request our application can respond to it. )
- Then we have to do couple of changes inside our controller action for which we need to return a pdf version.
This is how my Controller looks like.
class InvoicesController < ApplicationController
before_filter :authenticate_customer!, :only => [:index, :show]
def index
@invoices = Invoice.all_invoices(current_customer)
end
def show
@invoice = Invoice.find(params[:id])
respond_to do |format|
format.html
format.pdf do
pdf = InvoicePdf.new(@invoice, view_context)
send_data pdf.render, filename:
"invoice_#{@invoice.created_at.strftime("%d/%m/%Y")}.pdf",
type: "application/pdf"
end
end
end
endHere u can see inside my show controller i have created a respond block with html and pdf format. And inside the format.pdf block there is a send_data method we are calling
send_data pdf.render, filename:
"invoice_#{@invoice.created_at.strftime("%d/%m/%Y")}.pdf",
type: "application/pdf"And what it does is, that it sends the data for the pdf document. we can have couple of options passed to this send data method. Like here i have passed a filename option to name the pdf document. and the type option.
One more option you can use here is to pass the disposition: “inline” after type and what this will do is instead of downloading a pdf it would open in the browser.
Now to work more on our PDF document, we will create a new class.
app/pdfs/inovice_pdf
Good way would be creating a new directory called pdfs inside our apps folder and then creating a new file called inovice_pdf (this is what i have created) and then create a class inside that called InvoicePdf and inherit that with a prawn document.
class InvoicePdf < Prawn::Document
end
#then inside that we can have a initialize method
class InvoicePdf < Prawn::Document
def initialize(invoice, view)
super()
text "This is an order invoice"
end
endhere we gave a call to a super method and display the string that we need to show on our PDF.
- Now remember the format.pdf block inside the show action in Invoices controller. inside that we have a line
pdf = InvoicePdf.new(@invoice, view_context)Here we have instantiated the InvoicePdf. here @invoice is the invoice instance so it can be accessible inside our pdf document and to access to all the view helpers in our PDF document we would pass view_context as the argument.
- Restart your application.
And we are ready to go. now we have to make the changes inside the InvoicePdf class for the styling that we need to apply to our PDF document.
- Now inside our InvoicePdf class we need to set the @invoice and view_context.
def initialize(invoice, view)
super()
@invoice = invoice
@view = view
text "Invoice #{@invoice.id}"
end- Now you can create different method inside your InvoicePdf class as per what you want to show on your pdf.
For example to show your logo on the pdf we can have a logo method.
```ruby
def logo
logopath = "#{Rails.root}/app/assets/images/logo.png"
image logopath, :width => 197, :height => 91
end
```
and then give a call to that logo method inside your initialize method.and wow logo shows up on the pdf.
and this is how we can have separate method for separate section of our pdf.
For more styling options you can refer to http://prawn.majesticseacreature.com/manual.pdf.
I have created a standard invoice and have pasted the code below.You can modify it as you want your PDF to look like.
class InvoicePdf < Prawn::Document
def initialize(invoice, view)
super()
@invoice = invoice
@view = view
logo
thanks_message
subscription_date
subscription_details
subscription_amount
regards_message
end
def logo
logopath = "#{Rails.root}/app/assets/images/logo.png"
image logopath, :width => 197, :height => 91
move_down 10
draw_text "Receipt", :at => [220, 575], size: 22
end
def thanks_message
move_down 80
text "Hello #{@invoice.customer.profile.first_name.capitalize},"
move_down 15
text "Thank you for your order.Print this receipt as
confirmation of your order.",
:indent_paragraphs => 40, :size => 13
end
def subscription_date
move_down 40
text "Subscription start date:
#{@invoice.start_date.strftime("%d/%m/%Y")} ", :size => 13
move_down 20
text "Subscription end date :
#{@invoice.end_date.strftime("%d/%m/%Y")}", :size => 13
end
def subscription_details
move_down 40
table subscription_item_rows, :width => 500 do
row(0).font_style = :bold
columns(1..3).align = :right
self.header = true
self.column_widths = {0 => 200, 1 => 100, 2 => 100, 3 => 100}
end
end
def subscription_amount
subscription_amount = @invoice.calculate_subscription_amount
vat = @invoice.calculated_vat
delivery_charges = @invoice.calculated_delivery_charges
sales_tax = @invoice.calculated_sales_tax
table ([["Vat (12.5% of Amount)", "", "", "#{precision(vat)}"] ,
["Sales Tax (10.3% of half the Amount)", "", "","#{precision(sales_tax)}"],
["Delivery charges", "", "", "#{precision(delivery_charges)} "],
["", "", "Total Amount", "#{precision(@invoice.total_amount) } "]]),
:width => 500 do
columns(2).align = :left
columns(3).align = :right
self.header = true
self.column_widths = {0 => 200, 1 => 100, 2 => 100, 3 => 100}
columns(2).font_style = :bold
end
end
def subscription_item_rows
[["Description", "Quantity", "Rate", "Amount"]] +
@invoice.subscriptions.map do |subscribe|
[ "#{subscribe.description} ", subscribe.quantity,
"#{precision(subscribe.rate)} ",
"#{precision(subscribe.quantity * subscribe.rate)}" ]
end
end
def precision(num)
@view.number_with_precision(num, :precision => 2)
end
def regards_message
move_down 50
text "Thank You," ,:indent_paragraphs => 400
move_down 6
text "XYZ",
:indent_paragraphs => 370, :size => 14, style: :bold
end
endNow if we go to the address bar and type the url for the show action.
http://localhost:3000/invoices/1.pdf (press enter)
or you can have a link like this in your view
<%= link_to "Download invoice", invoice_path(invoice.id, :format => 'pdf') %>;the invoice would be downloaded. Remember at top i told you if you dont want to download and just show up in your browser just add this option to the send_data disposition: "inline"
send_data pdf.render, filename:
"invoice_#{@invoice.created_at.strftime("%d/%m/%Y")}.pdf",
type: "application/pdf", disposition: "inline"