2011-12-14 61 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指向遇到的問題。您可能需要在生產環境中實現動態並指向完整域,但這應該很簡單。

相關問題