附上大虾pdf到邮件

Attach Prawn pdf to email

我找了很多年了,似乎还是想不通,

我目前正在使用 prawn gem,我希望能够将 pdf 附加到 invoice controllers create action 中的 email。我目前可以通过 http://localhost:3000/invoices/297.pdf 从我的 invoices/show 页面 link 生成 pdf,但我不知道如何将此 pdf 附加到电子邮件。

目前我没有将生成的 PDF 存储在任何地方,我的邮件看起来像这样

邮寄者

class InvoiceMailer < ActionMailer::Base
default :from => "notifications@example.com"

 def invoice_email(user)
   @user = user
   mail(:to => user.email, :subject => "Invoice Recieved")
 end
end

我的 InvoicesController 创建操作

{...}
respond_to do |format|
  if @invoice.save
    InvoiceMailer.invoice_email(@invoice.user).deliver
    format.html { redirect_to invoice_url(@invoice, back_path: 
{...}

如何将我的发票作为附件添加到此邮件中?我需要先将发票存放在某个地方才能发送吗?

您需要 url 可以使用。如果您不想将其存储在数据库中,则可以选择任何云存储解决方案。

这里有一些关于向来自 rails guides on action mailer 的邮件程序添加附件的相关信息:

2.3.1 Adding Attachments

Action Mailer makes it very easy to add attachments.

Pass the file name and content and Action Mailer and the Mail gem will automatically guess the mime_type, set the encoding and create the attachment.

attachments['filename.jpg'] = File.read('/path/to/filename.jpg')

When the mail method will be triggered, it will send a multipart email with an attachment, properly nested with the top level being multipart/mixed and the first part being a multipart/alternative containing the plain text and HTML email messages.

如何执行此操作取决于 PDF 生成需要多长时间 and/or 它给您的服务器带来了多少负载以及您是否关心它。在我的例子中,我从用户生成的内容生成 PDF,我看到一些 PDF 创建时间在 30 秒以上的范围内。解决这个问题变成了 运行-the-job-somewhere-else 和 cache-it(无论是数据库还是云存储)问题。

@toddmetheny 非常正确地建议将云存储用于除最简单的解决方案之外的所有解决方案。如果您托管在像 Heroku 这样具有临时存储的东西上,或者如果您将 PDF 创建与用户请求发送的电子邮件分开(例如再次来自 Heroku,web dynos 与 worker dynos),它会变得更有趣。您可以将 PDF 生成到本地临时文件,但是当您需要在 运行ning 'worker'.

上的 Mailer 运行ning 中阅读时,该临时文件可能不存在

非常简单的选项

在您的 Mailer 中,您可以将 PDF 生成到本地文件,将其读回内存,然后附加:

def invoice_email(user)
  @user = user

  attachments['filename_for_user.pdf'] = generate_pdf_content

  mail(:to => user.email, :subject => "Invoice Recieved")
end

private

  # I had troubles trying to get Prawn to generate 'in memory'
  # so just write to, then read, then unlink a tempfile
  def generate_pdf_content
    pdf = some_method_that_generates_a_prawn_pdf_object
    Tempfile.create do |f|
      pdf.render_file f
      f.flush
      File.read(f)
    end
  end

我建议您从这里开始,让一切正常进行。

更复杂的选项

有一天,您可能希望将生成 PDF 的作业(这可能需要很长时间)与发送电子邮件的作业分开,后者通常要快得多。我这样做的方法是有一个生成 PDF 到本地 Tempfile 的工作,然后将该文件上传到 S3 存储并记录 S3 对象 ID(我在我的数据库中这样做,你可以把它作为一个工作属性来做你推来推去)。

完成后,该作业会创建一个新的邮件作业。邮件程序作业(可能在不同的服务器上执行)将 PDF 从 S3 存储下载到本地文件,然后将其添加到电子邮件中,就像上面的简单选项一样。