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" }
endWe 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)
endCreating 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
endSo 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.