2013-02-07 39 views
14

在Rails3中,我使用WickedPDF gem來呈現我的一個模型的PDF格式。這工作正常:/invoices/123返回HTML,/invoices/123.pdf下載PDF。從WickedPDF獲取PDF以通過Carrierwave進行附件

在我的Invoice模型中,我使用state_machine gem來跟蹤發票狀態。當發票從「未結帳」狀態變爲「已結帳」狀態時,我想要使用CarrierWave獲取發票PDF副本並將其附加到發票模型中。

我有三個部分分開工作:控制器創建PDF視圖,模型跟蹤狀態並在進行正確過渡時觸發回調,並且CarrierWave設置正確。不過,我有一段時間讓他們一起打好。

如果我只是想抓住發票的HTML版本,我可以從模型中撥打render_to_string。但render_to_string似乎在收到PDF二進制文件時會窒息。如果我能夠獲取數據流,那麼將這些數據寫入臨時文件並將其附加到上傳器非常容易,但我無法弄清楚如何獲取數據流。

有什麼想法?下面的代碼:

發票控制器

def show 
    @invoice = @agg_class.find(params[:id]) 

    respond_to do |format| 
    format.pdf do 
     render_pdf 
    end 
    format.html # show.html.erb 
    format.json { render json: @aggregation } 
    end 
end 

...

def render_pdf(options = {}) 
    options[:pdf] = pdf_filename 
    options[:layout] = 'pdf.html' 
    options[:page_size] = 'Letter' 
    options[:wkhtmltopdf] = '/usr/local/bin/wkhtmltopdf' 
    options[:margin] = { 
    :top  => '0.5in', 
    :bottom => '1in', 
    :left  => '0in', 
    :right => '0in' 
    } 
    options[:footer] = { 
    :html => { 
     :template => 'aggregations/footer.pdf.haml', 
     :layout  => false, 
    } 
    } 
    options[:header] = { 
    :html => { 
     :template => 'aggregations/header.pdf.haml', 
     :layout  => false, 
    } 
    } 
    render options 
end 

Invoice.rb

def create_pdf_copy 

    # This does not work.  
    pdf_file = ApplicationController.new.render_to_string(
    :action => 'aggregations/show', 
    :format => :pdf, 
    :locals => { 
     :invoice => self 
    } 
) 

    # This part works fine if the above works. 
    unless pdf_file.blank? 
    self.uploads.clear 
    self.uploads.create(:fileinfo => File.new(pdf_file), :job_id => self.job.id) 
    end 

end 

UPDATE實測值的溶液中。

def create_pdf_copy 

    wicked = WickedPdf.new 

    # Make a PDF in memory 
    pdf_file = wicked.pdf_from_string( 
     ActionController::Base.new().render_to_string(
      :template => 'aggregations/show.pdf.haml', 
      :layout  => 'layouts/pdf.html.haml', 
      :locals  => { 
       :aggregation => self 
      } 
     ), 
     :pdf => "#{self.type}-#{self}", 
     :layout => 'pdf.html', 
     :page_size => 'Letter', 
     :wkhtmltopdf => '/usr/local/bin/wkhtmltopdf', 
     :margin => { 
      :top  => '0.5in', 
      :bottom => '1in', 
      :left  => '0in', 
      :right => '0in' 
     }, 
     :footer => { 
      :content => ActionController::Base.new().render_to_string({ 
       :template => 'aggregations/footer.pdf.haml', 
       :layout => false 
      }) 
     }, 
     :header => { 
      :content => ActionController::Base.new().render_to_string({ 
       :template => 'aggregations/header.pdf.haml', 
       :layout => false 
      }) 
     } 
    ) 

    # Write it to tempfile 
    tempfile = Tempfile.new(['invoice', '.pdf'], Rails.root.join('tmp')) 
    tempfile.binmode 
    tempfile.write pdf_file 
    tempfile.close 

    # Attach that tempfile to the invoice 
    unless pdf_file.blank? 
     self.uploads.clear 
     self.uploads.create(:fileinfo => File.open(tempfile.path), :job_id => self.job.id) 
     tempfile.unlink 
    end 

end 
+0

好吧,我有它的工作。第一步是圍繞WickedPDF忽略全局配置設置而不是在控制器上運行的事實。步驟2:使用Tempfile將PDF輸出保存爲二進制模式tempfile,然後將其附加到Carrierwave。編輯原始帖子以反映解決方案。 – lascarides

+0

你可以給我更多關於第1步的細節嗎?我本地有一箇舊版本的wkhtmltopdf,用render_to_string導出就好了。在服務器上我有wkhtmltopdf 0.11.0和render_to_string的作品,但PDF是不可讀的。升級到0.11.0本地和render_to_string扼流圈..似乎是你有同樣的問題.. FYI:我使用'file = StringIO (render_to_string(options))'所以我可以跳過Tempfile。這是與回形針,但你可以試試看,如果你喜歡這個想法。 –

+2

很高興你解決了它。你應該寫出你的解決方案作爲答案,然後接受你的答案。在回答你自己的問題時沒有傷害! – sockmonk

回答

6

解決方案:

def create_pdf_copy 

    wicked = WickedPdf.new 

    # Make a PDF in memory 
    pdf_file = wicked.pdf_from_string( 
     ActionController::Base.new().render_to_string(
      :template => 'aggregations/show.pdf.haml', 
      :layout  => 'layouts/pdf.html.haml', 
      :locals  => { 
       :aggregation => self 
      } 
     ), 
     :pdf => "#{self.type}-#{self}", 
     :layout => 'pdf.html', 
     :page_size => 'Letter', 
     :wkhtmltopdf => '/usr/local/bin/wkhtmltopdf', 
     :margin => { 
      :top  => '0.5in', 
      :bottom => '1in', 
      :left  => '0in', 
      :right => '0in' 
     }, 
     :footer => { 
      :content => ActionController::Base.new().render_to_string({ 
       :template => 'aggregations/footer.pdf.haml', 
       :layout => false 
      }) 
     }, 
     :header => { 
      :content => ActionController::Base.new().render_to_string({ 
       :template => 'aggregations/header.pdf.haml', 
       :layout => false 
      }) 
     } 
    ) 

    # Write it to tempfile 
    tempfile = Tempfile.new(['invoice', '.pdf'], Rails.root.join('tmp')) 
    tempfile.binmode 
    tempfile.write pdf_file 
    tempfile.close 

    # Attach that tempfile to the invoice 
    unless pdf_file.blank? 
     self.uploads.clear 
     self.uploads.create(:fileinfo => File.open(tempfile.path), :job_id => self.job.id) 
     tempfile.unlink 
    end 

end 
相關問題