Creating PDF Documents in Ruby on Rails

Tháng Ba 26, 2009

Source: http://jimneath.org/2009/02/16/creating-pdf-documents-in-ruby-on-rails/

Those of you that follow me on Twitter will probably know that I’ve spent the last week or so trying to find a decent way of generating PDF documents from a Rails application. I finally found a solution that suited my needs so I thought I’d share it with you lovely people.

Initial Probing

After my first round of googling I came across 2 solutions that people seem to be using:

I’ll admit I didn’t really look too much into PDF::Writer but I did spend a couple of days playing around with Prawn.

All was going well until I ran into certain situations. The two main problems I had with Prawn were that it’s too difficult to style things as I wanted to and generating a table of contents. I might be missing something but I couldn’t get my head around how to solve the latter.

I don’t want to learn a new syntax to define my PDF documents. I don’t want to learn a new way of styling things. I like my HTML and CSS.

WHERE’S MY HTML AND CSS?!

Introducing Prince

Prince XML is a command line program that takes your spiffy html and css and returns a nicely formatted PDF document for you.

Prince is a computer program that converts XML and HTML into PDF documents. Prince can read many XML formats, including XHTML and SVG. Prince formats documents according to style sheets written in CSS.

See, I told you.

So, we’ve got prince xml, but what about hooking it up with rails?

Introducing Princely

Princely is a fantastic plugin by Michael Bleigh, author of other great plugins, such as subdomain-fu and acts-as-taggable-on.

Princely is basically a wrapper around the Prince API. It allows you to define your PDF views as templates like show.pdf.erb. You can write your views as you would normal html views and Princely will return a pdf when you hit those pages.

def show
  respond_to do |format|
    format.html
    format.pdf do
      render :pdf => "filename", :stylesheets => ["application", "prince"], :layout => "pdf"
    end
  end
end

Awesome, right?

Installing Prince and Princely

To install Prince XML, visit the download page and chose the package which suits your needs. Done.

Next, to install Princely, run the following command from your Rails app.

script/plugin install git://github.com/mbleigh/princely.git

Page Numbering

To set the page numbers of you PDFs you’ll need to use the counter attribute of CSS3.

@page {
  @bottom-left {
    content: counter(page);
  }
}

This snippet of code will, funnily enough, add the current page number to the bottom left of each page. That’s all there is to it.

If you’d prefer to show the page number along with the total number of pages, you can use the following:

@page {
  @bottom-left {
    content: "Page " counter(page) " of " counter(pages);
  }
}

Table of Contents

If you’re creating a large PDF with a few sections, it’s generally a good idea to include a table of contents at the start of your document.

The first thing you need to do, is output a list of links at the start of you document that link to internal anchors:

<ul id="toc">
  <li><a href="#ruby">Chapter 1: An Introduction to Ruby</a></li>
  <li><a href="#rails">Chapter 2: Hello, Rails!</a></li>
  <li><a href="#prince">Chapter 3: Pump it up, Prince!</a></li>
</ul>

This will give you a list, that looks something along the lines of the following image:

toc

Now with a bit of CSS magic, we can add the page numbers from our PDF to the table of contents. Ready for this? Go!

ul#toc a::after
{
  content: leader('.') target-counter(attr(href), page);
}

That’s it. attr(href) finds the target of the link. target-counter finds the page that the anchor is on and the leader call just pads the left had side with periods. Win.

That nifty bit of CSS should leave you with something looking like this:

toc unstyled

A bit more CSS to tidy it up a bit:

ul#toc ul {
	margin: 0;
	list-style: none;
	padding: 0;
}

ul#toc a {
	text-decoration: none;
}

ul#toc li {
	margin: 0;
	padding: 0;
	list-style: none;
}

And then we should have something that looks a bit nicer:

toc styled

That’s all there is to it. Easy, right?

Metadata

Prince writes metadata to your PDFs via the meta tags in your html. You can set the document author, subject and keywords using the following:

<head>
  <title>PDF Generation</title>
  <meta name="author" content="Jim Neath"/>
  <meta name="subject" content="Generating PDFs with Prince"/>
  <meta name="keywords" content="PDF, prince, ruby, rails"/>
</head>

Further Reading

Gửi phản hồi

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Log Out / Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Log Out / Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Log Out / Thay đổi )

Google+ photo

Bạn đang bình luận bằng tài khoản Google+ Log Out / Thay đổi )

Connecting to %s

%d bloggers like this: