HTML to PDF in Ruby on Rails
Explore modern solutions for converting HTML to PDF in Rails applications using Ruby-Puppeteer, moving beyond legacy tools like WickedPDF and Prawn.
Converting HTML to PDF has long been a staple in web development, particularly for applications that need to generate invoices, reports, or any printable content. Traditionally, the Rails community has relied on gems like WickedPDF and Prawn. However, these tools have their limitations, and newer, more robust solutions like Puppeteer have emerged. In this post, I'll walk you through the current landscape and show you how to use the ruby-puppeteer gem to convert HTML to PDF in your Rails application.
Legacy Solutions
WickedPDF has long been a popular choice for developers, utilizing the wkhtmltopdf command-line tool, which employs Webkit to render HTML and CSS. However, the maintenance and updates for WickedPDF have dwindled, raising concerns about its long-term sustainability. While it worked for some legacy projects, we faced significant challenges trying to get it functional again during our Ruby/Rails upgrade processes. With the wkhtmltopdf repository being archived and no updates in nearly five years, we had to question whether it was worth the effort to continue using it or if it was time to look for an alternative solution.
Prawn is another popular gem in the Rails ecosystem, known for its flexibility and powerful PDF generation capabilities. However, Prawn isn't designed to convert HTML to PDF. Instead, it provides a programmatic API to create PDFs from scratch, which can be time-consuming and less intuitive for those who prefer to work directly with HTML and CSS. We already had the HTML and CSS working in our project and wanted to find the "path of least resistance" to fix this relatively trivial problem from an outside perspective.
Enter Ruby-Puppeteer
After extensive research, I aimed to find a solution using Puppeteer. Initially, I developed a Node.js-based approach that involved spinning up a browser pool to handle incoming requests. However, this approach turned out to be too cumbersome to deploy, secure, and set up in our development environments.
I then discovered Ruby-Puppeteer. Ruby-puppeteer is a gem that wraps the functionality of Puppeteer, a Node library which provides a high-level API to control Chrome or Chromium over the DevTools Protocol. It can render HTML and CSS using the latest web standards, making it a powerful tool for converting HTML to PDF.
Here's how you can integrate ruby-puppeteer into your Rails application:
Setting Up Ruby-Puppeteer
First, you'll need to install the ruby-puppeteer gem. Add it to your Gemfile and bundle install:
# Gemfile
...
gem 'puppeteer-ruby'
... Run the bundle command to install the gem:
bundle install Creating a Service to Generate PDFs
Next, create a service in your Rails app to handle the PDF generation. You can place this service in app/services and name it pdf_generator_service.rb.
# app/services/pdf_generator_service.rb
require 'puppeteer-ruby'
class PdfGeneratorService
def initialize(html_content)
@html_content = html_content
end
def generate_pdf
tempfile = Tempfile.new(['document', '.pdf'])
Puppeteer.launch do |browser|
page = browser.new_page
page.set_content(@html_content)
page.pdf(path: tempfile.path, format: 'A4')
end
File.read(tempfile.path)
ensure
tempfile.close
tempfile.unlink
end
end Using the Service in Your Controller
Now, you can use the PdfGeneratorService in your Rails controller to generate PDFs from HTML content.
# app/controllers/documents_controller.rb
class DocumentsController < ApplicationController
def create_pdf
html_content = render_to_string(template: 'documents/show', layout: false)
pdf_content = PdfGeneratorService.new(html_content).generate_pdf
send_data pdf_content, filename: 'document.pdf', type: 'application/pdf'
end
end Drawbacks of Using Ruby-Puppeteer
While Ruby-Puppeteer is powerful, it's not without its challenges:
- Dependency on Node.js: Unlike Ruby gems, Puppeteer requires Node.js, adding another layer to your tech stack.
- Resource Intensive: Puppeteer runs a full instance of Chromium, which can be resource-intensive, especially under heavy load.
- Deployment Complexity: Ensuring that Puppeteer and Chromium are correctly installed and running on your production environment can be tricky. Docker can simplify this, but it adds complexity.
Conclusion
Switching from traditional tools like WickedPDF and Prawn to Ruby-Puppeteer can offer more flexibility and modern web standards support for converting HTML to PDF in Rails. While there are some drawbacks, the benefits of using a robust and actively maintained tool like Puppeteer can be significant, especially for complex PDF generation needs.