Easy PDFs from Rails

Rails to PDF

Seth Banks at Subimage has made it easy to generate PDFs directly from Rails. Seth uses Prince XML to generate the PDF with some custom Ruby handlers that he wrote. It seems easy, but more importantly, it seems flexible.

I gave it a quick test drive with great results, but I had to make a few modifications that Seth doesn’t make clear. If you want to try it, read his original post, then follow these steps.

  • 1. Download Prince XML and unzip it if necessary.
  • 2. Open a command-line window, navigate to the Prince XML folder, and type sudo ./install.sh. I installed it in the default location “/usr/local/”.
  • 3. Download Seth’s files: prince.rb and pdf_helper.rb
  • 4. prince.rb should require no changes, put it in your Rails application’s “lib” folder.
  • 5. Consider pdf_helper.rb to be a “usage example”; parts of it are specific to Seth’s setup and will need to be customized for your needs. You can either put the file in your Rails application’s “lib” folder or use the same code directly in your controller. For real world usage, you will probably want to completely rewrite his two examples for your needs but to get up and running quickly simply change a few key parts as detailed in the next step.
  • 6. Open up pdf_helper.rb. Where it calls prince.add_style_sheets() change those style sheets to be a list of your stylesheets.
  • 7. Also in pdf_helper.rb: Where it calls render_to_string() change the :layout to be your layout name.
  • 8. Call the helper in your controller. Here’s an example of how I did it:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class ReportsController < ApplicationController

  def sales_report
    # code removed...
    # the idea is that this action would normally render
    # a sales report to the browser
  end

  # to allow use of the modified version of Seth's helper
  include PdfHelper

  def sales_report_pdf
    # you'll still need to prepare the report
    sales_report
    # call a method in Seth's helper
    # pass it the path to the view template and the PDF name
    make_and_send_pdf('/reports/sales_report', 'sales_report.pdf')
  end

end
  • 9. Try it! You may need to make CSS changes to get pretty output, but you should get a PDF.

Thanks, Seth!

It would be cool if someone made this into a plug-in and the PdfHelper could be made more universal and called using render_pdf() or render_prince_pdf(). It would be extra-super-cool if it actually extended ActiveRecord’s render method, something like:

1
2
3
render(:pdf => 'sales_report',
    :file => 'reports/sales_report',
    :layout => 'reports')

Let me know if anyone does!

Bookmark and Share

17 Responses to “Easy PDFs from Rails”

  1. mikedc55 Says:

    I keep getting this error:
    ——————
    You have a nil object when you didn’t expect it.
    The error occurred while evaluating nil.chomp
    ——————

    I’m on winxp btw.

    Any ideas on what the problem could be?

  2. Kevin Skoglund Says:

    It’s difficult to say because I didn’t write Prince or the Prince helper.

    But here’s my advice: Check your customizations and make sure you are generating the report (and are getting some data) before outputing the PDF. If that doesn’t work, search inside pdf_helper.rb and prince.rb for ‘chomp’. That may give you a clue as to what variable is nil when it shouldn’t be.

  3. mikedc55 Says:

    Thanks Kevin.
    I got it to work…finally.
    I edited the prince.rb file as follows:

    - @exe_path = “C:\\Program Files\\Prince\\Engine\\bin\\prince” .chomp
    - uncommented the logger method because it gave me errors. (had this same error on osx as well)
    - plus I added the following line in the pdf_from_string method; pdf.binmode
    so now it’s:
    pdf = IO.popen(path, “w+”)
    pdf.binmode
    …etc…

  4. Riggasconi Says:

    THANK YOU!

  5. khelll Says:

    am getting garbled text when using utf8

    am working on ubuntu 7.04

    is that related to prince.rb , specifically line 66 when passing the html string: pdf.puts(string)

    ??

    also i found out that it adds ’script/../config/../public’ to each image src attribute…. and so it misses the paths of all images. what to do?

  6. khelll Says:

    ok i think i could manage the image src issue , he handles that in pdf_helper.rb line 27
    so once omitting or commenting it things goes on.

    still the issue of utf8, any solution?

  7. mikedc55 Says:

    @ khelll

    Have you tried the Princexml forum?
    http://www.princexml.com/bb/viewtopic.php?t=227&highlight=utf

  8. khelll Says:

    ok after the test, i turned out that prince is considering it the input string as latin1 or ISO_8859-1, so my question is : is there an option to tell prince abt the encoding.
    i need to let prince consider the received code as UTF-8….
    thanks for help

  9. kadoudal Says:

    thanks for your clear advices…
    I am trying to get it running into my project now..
    you wrote.. in the sales_report action
    this action would normally render
    # a sales report to the browser

    do I need to render it in the action ? into a views/reports/sales_report.rhtml … with a layout/reports.rhtml layout ?
    how should I handle the views with a layout ? is that correct ?

    that’s what the following lines seems to indicate , no need for template extension /reports/sales_report.rhtml

    make_and_send_pdf(’/reports/sales_report’, ’sales_report.pdf’)

    when doing that .. I get an error

    Missing template …./config/../app/views/documents/sales_report_pdf.rhtml

    thanks again for your advices

  10. Mulasse Says:

    Khelll => in , in <meta http-equiv… “charset=UTF-8″ instead of “charset=iso-8859-1″ in your document layout.

    I’ve got probs with gsub(src) too.
    If i comment the line, got nil exception
    If i transform the pattern with /src=”\//, nil exception too.
    I really don’t understand, especially for the first case, if someone has an idea.

    thanks

  11. Robert Says:

    hi there,

    how can i pass ‘/reports/sales_report?id=12345′ instead of /reports/sales_report? i wanted to display some dynamic contents in pdf. thanks!

  12. Nimesh Says:

    I cant get the images displayed into my application. I have also removed the line pdf_helper.rb line 27
    . but still not getting the images displayed…

  13. Ufolog Says:

    2 Robert write before sales_report params[:id] = 12345 and then make_and_send_pdf(’/reports/sales_report’, “123.pdf”)

  14. Brijesh Shah Says:

    I used pricely pluging. Prince is installed in /usr/local/lib but still i am getting this error
    sh: Usage:: command not found
    prince: warning: failed to load external entity “[OPTIONS]”
    prince: [OPTIONS]: error: could not load input file
    prince: warning: failed to load external entity “file.xml”
    prince: file.xml: error: could not load input file
    prince: warning: failed to load external entity “Convert”
    prince: Convert: error: could not load input file
    prince: warning: failed to load external entity “file.xml”
    prince: file.xml: error: could not load input file
    prince: warning: failed to load external entity “to”
    prince: to: error: could not load input file
    prince: error: no input documents to process
    prince: warning: failed to load external entity “[OPTIONS]”
    prince: [OPTIONS]: error: could not load input file
    prince: warning: failed to load external entity “doc.html”
    prince: doc.html: error: could not load input file
    prince: warning: failed to load external entity “Convert”
    prince: Convert: error: could not load input file
    prince: warning: failed to load external entity “doc.html”
    prince: doc.html: error: could not load input file
    prince: warning: failed to load external entity “to”
    prince: to: error: could not load input file
    prince: warning: failed to load external entity “out.pdf”
    prince: out.pdf: error: could not load input file
    prince: error: no input documents to process
    prince: warning: failed to load external entity “[OPTIONS]”
    prince: [OPTIONS]: error: could not load input file
    prince: warning: failed to load external entity “FILES…”
    prince: FILES…: error: could not load input file
    prince: warning: failed to load external entity “Combine”
    prince: Combine: error: could not load input file
    prince: warning: failed to load external entity “multiple”
    prince: multiple: error: could not load input file
    prince: warning: failed to load external entity “files”
    prince: files: error: could not load input file
    prince: warning: failed to load external entity “to”
    prince: to: error: could not load input file
    prince: warning: failed to load external entity “out.pdf”
    prince: out.pdf: error: could not load input file
    prince: error: no input documents to process
    sh: line 5: Try: command not found
    sh: line 6: –input=html: command not found

    Can you tell me how to solve this?

  15. Leo Says:

    Can’t make it work..

    Im using it within a show method like this
    _______________________________________
    include PdfHelper
    def show
    @user = User.find(params[:id])
    respond_to do |format|
    format.html # show.html.erb
    format.xml { render :xml => @user }
    make_and_send_pdf(’/users/show’,'leo.pdf’)
    end
    end
    _______________________________________
    And I’ve got te following error

    ArgumentError in UsersController#show

    wrong number of arguments (2 for 1)
    _______________________________________

    Any ideas?

  16. alexey Says:

    hm, also having problem with utf-8 processing..
    i have in layout of pdf prince ..

  17. alexey Says:

    ok, sorry :) my mistake
    :layout => “prince_pdf” instead of “prince-pdf”
    ^_^

Leave a Reply