Pages

Thursday, July 9, 2015

Send PDF attachments from Rails with WickedPdf and ActionMailer

In almost any web application you create, the question of generating PDF files will pop up pretty soon. 

Setup

As always, using a ruby gem in rails is pretty simple, you just add a couple of lines to the Gemfile
gem 'wicked_pdf'
#we need the new binary here, so that we can be OS independent
gem 'wkhtmltopdf-binary', github: 'pallymore/wkhtmltopdf-binary-edge', tag: 'v0.12.2'

Usage

This setup will work pretty straightforward in the controllers, because WickedPdf registers :pdf request format, and you can respond to it in the same fashion as html or js in a respond_to block. Code below is copied from the WickedPdf Readme page.

class ThingsController < ApplicationController
  def show
    respond_to do |format|
      format.html
      format.pdf do
        render pdf: "file_name" # Excluding ".pdf" extension.
      end
    end
  end
end
That part was pretty easy, and you can configure the pdf render with a lot of options that are mentioned in the advanced configuration section of the WickedPdf Readme

Generating PDF from ActionMailer

The issue when trying to generate the PDF from ActionMailer is that there is no request, so you have to render the html in a different way. In a nutshell, you want to render the template to a string, and then forward that string (html) to the wkhtmltopdf. This is the same way the gem work when rendering pdf from the controller, but it is worth mentioning once more.
We will use a method that exists on the AbstractController::Rendering and it is called render_to_string So we can do something like this in the mailer:
class TodoMailer < ActionMailer::Base
  #...
  def pdf_attachment_method(todo_id)
    todo = Todo.find(todo_id)
    attachments["todo_#{todo.id}.pdf"] = WickedPdf.new.pdf_from_string(
      render_to_string(pdf: 'todo', template: 'todo.pdf.erb', layout: 'pdf.html'), { :hash_with_wickedpdf_options }
    )
    mail(to: todo.owner.email, subject: 'Your todo PDF is attached', todo: todo)
  end
end
By using this approach, we can easily send a PDF attachment from an ActionMailer method. You can do this for any Rails template you want, but be sure to test everything before putting it into production.

No comments:

Post a Comment