Sending prawn documents with ActionMailer

Problem: How to send a prawn pdf wich normally is generated by a controller.

and keeping it DRY

Required: Prawn & prawnto

first: Make your prawnto settings global with an initializer

PRAWN_DEFAULT_STYLES = {
  :page_size   => 'A4',
  :inline      => true,
  :left_margin => 50
}

second: create a ActionMailer

./script/generate mailer recipient_mailer invoice

third: edit the generated recipient mailer (note: because I’m using the views from the controller I’ve removed the autogenerated invoice.erb. Otherwise these will be included as well)

# Include (optional) controller helpers
class Prawn::Document
  include PdfHelper
end
 
class RecipientMailer < ActionMailer::Base
  # explicitly require prawn, so we get all the goodieness
  require 'prawn'
  require "prawn/format"
  require "prawn/layout"
 
  def invoice(ledger_item)
    subject    "The subject"
    recipients '"Name" <info@example.com>'
    from       '"Name" <info@example.com>'
    sent_on    Time.now
    content_type    "multipart/mixed"
 
    # the templates live in RAILSROOT/app/views/documents
    # these are views normally generated by the DocumentsController
    part(:content_type => "multipart/alternative") do |alternative|
      alternative.part "text/plain" do |p|
        p.body = render_message("documents/show.txt", :ledger_item => ledger_item)
      end
 
      alternative.part "text/html" do |p|
        p.body = render_message("documents/show.html", :ledger_item => ledger_item)
      end
    end
 
    # And here is the magic:
    # probably could be refactored, but it's working!
    attachment "application/pdf" do |a|
      a.filename = "#{ledger_item.period}.pdf"
 
      template = File.open(File.join(Rails.root, 'app', 'views', 'documents', 'show.pdf.prawn')).read
 
      pdf = Prawn::Document.new(PRAWN_DEFAULT_STYLES);
      pdf.instance_eval do
        @ledger_item = ledger_item
        eval(template)
      end
 
      a.body = pdf.render
    end
 
  end
end

3 Responses to “Sending prawn documents with ActionMailer”

  1. Nick V says:

    Thank you so much….i was just hacking at this for a couple hours, and you happened to just post this today which was really fortunate for me. Big ups to you man!!!!

  2. You are a life saver.
    I was facing the possibility of moving all my Prawn files away from being views into being external prawn pdf generators. And not looking forward to it.

  3. Zoli says:

    Thanks, Leon, it’s an extremely useful post!

    If you need to use helper methods in the .prawn template, can add these lines to the application (I’ve created a lib/class_extensions.rb for this kind of class extensions):

    class Prawn::Document
    include ApplicationHelper
    include DocumentsHelper

    end