2

我正在使用 Prawn 从我的控制器生成 PDF,当直接在 url 访问时,它可以完美运行,IE localhost:3000/responses/1.pdf

但是,当我尝试动态生成此文件以包含在 Mailer 中时,一切都冻结并超时。

我尝试了各种生成/附加文件的方法,但都没有改变结果。

我还尝试修改 Net::HTTP 的超时,但无济于事,它只需要更长的时间才能超时。

如果我在 Rails 控制台上运行这个命令,我会收到一个 PDF 数据流。

Net::HTTP.get('127.0.0.1',"/responses/1.pdf", 3000)

但是如果我在我的控制器中包含这段代码,它就会超时。

我尝试了两种不同的方法,但都反复失败。

方法一 控制器:

http = Net::HTTP.new('localhost', 3000)
http.read_timeout = 6000
file = http.get(response_path(@response, :format => 'pdf')) #timeout here
ResponseMailer.confirmComplete(@response,file).deliver #deliver the mail!

方法1邮寄:

def confirmComplete(response,file)
  email_address = response.supervisor_id
  attachments["test.pdf"] = {:mime_type => "application/pdf", :content=> file}
  mail to: email_address, subject: 'Thank you for your feedback!'
end

上面的代码超时。

方法2控制器:

ResponseMailer.confirmComplete(@response).deliver #deliver the mail!

方法2邮寄:

def confirmComplete(response)
email_address = response.supervisor_id
attachment "application/pdf" do |a|
    a.body = Net::HTTP.get('127.0.0.1',"/responses/1.pdf", 3000) #timeout here
    a.filename = "test.pdf" 
end
mail to: email_address, subject: 'Thank you for your feedback!'

结尾

如果我切换 a.body 和 a.filename,它首先会出错

undefined method `filename=' for #<Mail::Part:0x007ff620e05678>

我发现的每个示例都有不同的语法或建议,但没有解决 Net::HTTP 超时的问题。导轨 3.1,红宝石 1.9.2

4

2 回答 2

2

问题是,在开发中,您只运行一个服务器进程,它正忙于生成电子邮件。该过程正在发送另一个请求(向自身)以生成 PDF 并等待响应。对 PDF 的请求基本上在服务器上排队,以便它可以获取它的 PDF,但是服务器正忙于生成电子邮件并等待获取 PDF 才能完成。因此,您将永远等待。

您需要做的是启动第二个服务器进程......

script/rails server -p 3001

然后用类似...的东西获取您的PDF

args = ['127.0.0.1','/responses/1.pdf']
args << 3001 unless Rails.env == 'production'
file = Net::HTTP.get(*args)

顺便说一句,根据您在生产机器上运行的服务器,您可能会遇到指向 127.0.0.1 的问题。您可能需要在生产中使其动态化并指向整个域,但这应该很容易。

于 2011-12-14T21:30:44.483 回答
1

我同意https://stackoverflow.com/users/811172/jon-garvin的分析,即您只运行一个服务器进程,但我会提到另一种解决方案。重构您的 PDF 生成,因此您不依赖于您的控制器。

如果您使用的是Prawnto,我猜您的视图如下

# app/views/response.pdf.prawn
pdf.text "Hello world"

将其移至您的Response模型:(或其他更合适的位置,例如演示者)

# app/models/response.rb
require 'tmpdir'
class Response < ActiveRecord::Base
  def pdf_path
    return @pdf_path if @pdf_generated == true
    @pdf_path = File.join(Dir.tmpdir, rand(1e11).to_s)
    Prawn::Document.generate(@pdf_path) do |pdf|
      pdf.text "Hello world"
    end
    @pdf_generated = true
    @pdf_path
  end

  def pdf_cleanup
    if @pdf_generated and File.exist?(@pdf_path.to_s)
      File.unlink @pdf_path
    end
  end
end

然后在你的ResponsesController你可以做:

# app/controllers/responses_controller.rb
def show
  @response = Response.find params[:id]
  respond_to do |format|
    # this sends the PDF to the browser (doesn't email it)
    format.pdf { send_file @response.pdf_path, :type => 'application/pdf', :disposition => 'attachment', :filename => 'test.pdf' }
  end
end

在您的邮件中,您可以执行以下操作:

# this sends an email with the PDF attached
def confirm_complete(response)
  email_address = response.supervisor_id
  attachments['test.pdf'] = {:mime_type => "application/pdf", :content => File.read(response.pdf_path, :binmode => true) }
  mail to: email_address, subject: 'Thank you for your feedback!'
end

由于您在 tmpdir 中创建了它,因此当您的服务器重新启动时它会被自动删除。您也可以调用清理函数。

最后一点:您可能想要使用不同的模型名称SupervisorReport或其他名称 -Response以后可能会给您带来命名空间的麻烦)

于 2011-12-14T23:20:19.000 回答