ActiveMailer PDF Email Attachments with Paperclip
Jason Dugdale
Let's say we have a Report
model, which has PDFs as Paperclip attachments:
/app/models/report.rb
class Report < ActiveRecord::Base
belongs_to :user
has_attached_file :pdf
validates_attachment :pdf, content_type: { content_type: "application/pdf" }
end
We want to automate sending out a report by email each week to the user who created the report (this post won't cover the automation; use something to automate that, like a CRON job, or the Clockwork gem).
For this example, I've set up an ActionMailer mailer to send the email, and an ActiveJob job to generate the PDF from values in the Report object.
Creating the ActiveJob job
rails g job generateReportPdf
/app/jobs/generate_report_pdf_job.rb
class GenerateReportPdfJob < ActiveJob::Base
queue_as :default
def perform(args)
@report = Report.find args[:report_id]
# create an instance of ActionView, so we can use the render method outside of a controller
av = ActionView::Base.new()
av.view_paths = ActionController::Base.view_paths
# need these in case your view constructs any links or references any helper methods.
av.class_eval do
include Rails.application.routes.url_helpers
include ApplicationHelper
end
pdf_html = av.render template: 'reports/generate_pdf', layout: 'layouts/pdf', locals: {report: @report}
# use wicked_pdf gem to create PDF from the doc HTML
doc_pdf = WickedPdf.new.pdf_from_string(
pdf_html,
page_size: 'Letter',
javascript_delay: 6000
)
# save PDF to disk
pdf_path = Rails.root.join('tmp/reports', "#{@report.id}_#{Date.today.iso8601}.pdf")
File.open(pdf_path, 'wb') do |file|
file << doc_pdf
end
@report.pdf = File.open pdf_path
@report.save!
# The report has now been saved elsewhere using Paperclip; we don't need to store it locally
File.delete(pdf_path) if File.exist?(pdf_path)
end
Creating the ActionMailer mailer
Now we create the mailer which will call out to this ActiveJob job to generate the PDF:
rails g mailer reportPdf
/app/mailers/report_pdf.rb
class ReportPdf < ApplicationMailer
def send_mail(report_id:)
@report = Report.find report_id
GeneratePdfJob.perform_now(report_id: @report.id)
@report.reload
attachments["report_#{Date.today.iso8601}.pdf"] = {
mime_type: 'application/pdf',
content: open(@report.pdf.expiring_url).read
}
mail(
to: @report.user.email,
subject: "Weekly PDF Email: #{Date.today.iso8601}",
)
end
end
So now all we need to do is call ReportPdf.send_mail(report_id: @report.id)
to generate and send an email with a PDF attachment, powered by Paperclip. The PDF generation is done via the wicked_pdf gem.