Value driven web development

Generate PDFs in Rails with RFPDF

December 19th, 2007

1, Install railsrfpdf plugin ruby script/plugin install http://cnruby.googlecode.com/svn/trunk/rails-projects/infoq_rfpdf/vendor/plugins/railsrfpdf/

2, add new Mime type to environment.rb: Mime::Type.register “application/pdf”, :pdf

3, in the controller

1
2
3
4
5
6
7
8
9
10
11
respond_to do |format| 
  format.html # show.rhtml 
  format.xml  { render :xml => @page.to_xml } 
  format.pdf do 
    pdf = FPDF.new 
    pdf.AddPage 
    pdf.SetFont("Arial",'B',18) 
    pdf.Cell(100, 20, "Hello World") 
    send_data pdf.Output, :filename => "hello.pdf", :type => "application/pdf" 
  end 
end

Useful method in RPDF SetFont(string family [, string style [, float size]]) SetMargins(float left, float top [, float right]) SetTextColor(int r [, int g, int b]) SetXY(float x, float y) AddFont(string family [, string style [, string file]]) Cell(float w [, float h [, string txt [, mixed border [, int ln [, string align [, int fill [, mixed link]]]]]]]) Image(string file, float x, float y [, float w [, float h [, string type [, mixed link]]]]) Line(float x1, float y1, float x2, float y2) MultiCell(float w, float h, string txt [, mixed border [, string align [, int fill]]]) Rect(float x, float y, float w, float h [, string style])

A case in real world

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
    pdf = FPDF.new('portrait', 'pt', [800, 1380]) 
    pdf.SetAutoPageBreak(false) 
    pdf.AddPage 
    # draw a rectangle 
    pdf.SetFillColor(240, 240, 240) 
    pdf.Rect(0, 0, 800, 895, 'F')    pdf.Image("#{RAILS_ROOT}/public/images/a.jpg", 0, 0, 800, 600) 
    # add four images 
    pdf.Image("#{RAILS_ROOT}/public/images/b.jpg", 0, 700, 260) 
    pdf.Image("#{RAILS_ROOT}/public/images/c.jpg", 270, 700, 260) 
    pdf.Image("#{RAILS_ROOT}/public/images/d.jpg", 540, 700, 260) 
    # write text 
    txt = 'Agile Web Development' 
    pdf.SetFont("Arial", 'B', 38) 
    pdf.SetXY(0, 600) 
    pdf.Cell(800, 100, txt, 10, 1, 'C') 
    pdf.SetTextColor(10, 10, 10) 
    txt = 'What is Ruby FPDF?' 
    pdf.SetFont("Arial", 'B', 30) 
    pdf.SetXY(20, 920) 
    pdf.Cell(300, 30, txt, 10, 1) 
    txt = "Ruby FPDF is a Ruby port of Olivier Plathey's excellent PDF generator, /
 FPDF. FPDF is written in PHP, 
and as such can only be used From PHP scripts. /
Ruby FPDF, as the name suggests, is written in Ruby and /
can be used From Ruby scripts.    Ruby FPDF was ported and is maintained by Brian Ollenberger. /
 If you need to contact me, see the contact link abovenYou can download Ruby FPDF below. /
 It is released under a permissive license, similar to that of FPDF. I only ask that you retain the /
 copyright notice at the top of the source file. You may make modifications to FPDF, but if you /
redistribute those modifications, make it clear in a comment immediately before or after the /
 copyright notice that you have modified it. I also wouldn't mind if you sent patches back to me, /
 but you are not strictly required to do so." 
    pdf.SetFont("Arial", '', 18) 
    pdf.SetXY(20, 960) 
    pdf.MultiCell(500, 20, txt) 
    txt = 'Ruby | On | Rails' 
    pdf.SetFont("Arial", '', 24) 
    pdf.SetXY(540, 920) 
    pdf.Cell(260, 30, txt, 10, 1, 'C') 
    #draw rectangle 
    pdf.SetFillColor(240, 240, 240) 
    pdf.Rect(550, 960, 230, 300, 'F') 
    #write text 
    txt = "* Get Excitednn* Get Startedn* Get BetternnContactnnEnjoy Railsnenjoyrails@gmail.com" 
    pdf.SetFont("Arial", 'B', 18) 
    pdf.SetXY(560, 970) 
    pdf.MultiCell(220, 36, txt) 
    pdf.SetFillColor(170, 0, 1) 
    pdf.Rect(0, 1310, 800, 70, 'F') 
    txt = 'View this page at http://devblog.rorcraft.com/' 
    pdf.SetTextColor(255, 255, 255) 
    pdf.SetFont("Arial", '', 28) 
    pdf.SetXY(0, 1330) 
    pdf.Cell(800, 24, txt, 0, 0, 'C') 
    send_data pdf.Output, :filename => "hello_advance.pdf", :type => "application/pdf" 

Reference: 1: fpdf manual

2: How to Generate PDFs

3: PDF::Writer VS Ruby FPDF

4: Iconv Rdoc

5: fpdf website

If you use the date_select, datetime_select helepers you’ll most likely see this error when the user submit an invalid date e.g. (Feb 30). Rails will raise MultiparameterAssignmentErrors.

The easiest way to fix this is by using this plugin for validates_datetime http://agilewebdevelopment.com/plugins/validates_date_time

However I just found that it has a bug with datetime_select, where it parse the (day, hour, minute) into (hour, minute, seconds).

Here is why: on line 179 of validates_date_time.rb in the lib/ folder of the plugin.
1
2
3
4
5
6
7
8
    def extract_time_from_multiparameter_attributes(values)
        values.last( 3 ).map { |s| s.rjust(2, "0") }.join(":")
    end
    
    # change it to this, it'll fix the problem.
    def extract_time_from_multiparameter_attributes(values)
        values.last( values.size > 5 ? 3 : 2 ).map { |s| s.rjust(2, "0") }.join(":")
    end