在 Rails3 中,我使用WickedPDF gem
来呈现我的一个模型的 PDF 格式。这工作正常:/invoices/123
返回 HTML,/invoices/123.pdf
下载 PDF。
在我的 Invoice 模型中,我使用 state_machine gem 来跟踪 Invoice 状态。当发票从“未开票”状态变为“已开票”状态时,我想获取发票 PDF 的副本并使用 CarrierWave 将其附加到发票模型中。
我让三个部分分别工作:控制器创建 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
发票.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
更新找到了解决方案。
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