2011-12-14 66 views
2

我正在使用Prawn从我的控制器生成一个PDF文件,当直接访问这个url时,它完美地工作,I.E. localhost:3000/responses/1.pdf为什么Net :: HTTP在我试图访问对虾生成的PDF时超时?

但是,当我尝试生成包含在Mailer中的此文件时,所有内容都会冻结并超时。

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

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

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

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

但是,如果我有这个代码在我的控制器,它超时。

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

方法1 控制器:

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超时的问题。 Rails 3.1,Ruby 1.9.2

+0

你试着用`curl`或`来获取该PDF网址wget`? – 2011-12-14 19:45:47

回答

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可能让你在以后的命名空间麻烦)

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指向遇到的问题。您可能需要在生产环境中实现动态并指向完整域,但这应该很简单。

相关问题