Rails 3 ActionMailer and Wicked_PDF

Daniel D picture Daniel D · Mar 24, 2011 · Viewed 8.6k times · Source

I'm trying to generate emails with rendered PDF attachements using ActionMailer and wicked_pdf.

On my site, I'm using already both wicked_pdf and actionmailer separately. I can use wicked_pdf to serve up a pdf in the web app, and can use ActionMailer to send mail, but I'm having trouble attaching rendered pdf content to an ActionMailer (edited for content):

class UserMailer < ActionMailer::Base
  default :from => "[email protected]"

  def generate_pdf(invoice)
    render :pdf => "test.pdf",
     :template => 'invoices/show.pdf.erb',
     :layout => 'pdf.html'
  end

  def email_invoice(invoice)
    @invoice = invoice
    attachments["invoice.pdf"] = {:mime_type => 'application/pdf',
                                  :encoding => 'Base64',
                                  :content => generate_pdf(@invoice)}
    mail :subject => "Your Invoice", :to => invoice.customer.email
  end
end

Using Railscasts 206 (Action Mailer in Rails 3) as a guide, I can send email with my desired rich content, only if I don't try to add my rendered attachment.

If I try to add the attachment (as shown above), I get an attachement of what looks to be the right size, only the name of the attachment doesn't come across as expected, nor is it readable as a pdf. In addition to that, the content of my email is missing...

Does anyone have any experience using ActionMailer while rendering the PDF on the fly in Rails 3.0?

Thanks in advance! --Dan

Answer

Unixmonkey picture Unixmonkey · Apr 2, 2011

WickedPDF can render to a file just fine to attach to an email or save to the filesystem.

Your method above won't work for you because generate_pdf is a method on the mailer, that returns a mail object (not the PDF you wanted)

Also, there is a bug in ActionMailer that causes the message to be malformed if you try to call render in the method itself

http://chopmode.wordpress.com/2011/03/25/render_to_string-causes-subsequent-mail-rendering-to-fail/

https://rails.lighthouseapp.com/projects/8994/tickets/6623-render_to_string-in-mailer-causes-subsequent-render-to-fail

There are 2 ways you can make this work,

The first is to use the hack described in the first article above:

def email_invoice(invoice)
  @invoice = invoice
  attachments["invoice.pdf"] = WickedPdf.new.pdf_from_string(
    render_to_string(:pdf => "invoice",:template => 'documents/show.pdf.erb')
  )
  self.instance_variable_set(:@lookup_context, nil)
  mail :subject => "Your Invoice", :to => invoice.customer.email
end

Or, you can set the attachment in a block like so:

def email_invoice(invoice)
  @invoice = invoice
  mail(:subject => 'Your Invoice', :to => invoice.customer.email) do |format|
    format.text
    format.pdf do
      attachments['invoice.pdf'] = WickedPdf.new.pdf_from_string(
        render_to_string(:pdf => "invoice",:template => 'documents/show.pdf.erb')
      )
    end
  end
end