2013-02-07 96 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 
相关问题