In Rails3 verwende ich die WickedPDF gem
, um ein PDF-Format eines meiner Modelle zu rendern. Dies funktioniert einwandfrei: /invoices/123
gibt HTML zurück, /invoices/123.pdf
lädt ein PDF herunter.PDF von WickedPDF zum Anhängen über Carrierwave herunterladen
In meinem Rechnungsmodell verwende ich das Juwel "state_machine", um den Rechnungsstatus zu verfolgen. Wenn eine Rechnung vom Status "nicht fakturiert" in den Status "fakturiert" wechselt, möchte ich eine Kopie der PDF-Datei der Rechnung abrufen und sie mit CarrierWave an das Rechnungsmodell anhängen.
Ich habe die drei Teile getrennt arbeiten: der Controller erstellt eine PDF-Ansicht, das Modell verfolgt den Status und löst einen Rückruf beim richtigen Übergang, und CarrierWave ist richtig eingerichtet. Allerdings habe ich eine Menge Zeit, sie dazu zu bringen, gut miteinander zu spielen.
Wenn ich nur die HTML-Version der Rechnung greifen wollte, könnte ich render_to_string
aus dem Modell anrufen. Aber render_to_string
scheint beim Empfangen einer PDF-Binärdatei zu ersticken. Wenn ich einen Datenstrom zurückbekomme, ist es ziemlich einfach, diese Daten in eine temporäre Datei zu schreiben und sie an den Uploader anzuhängen, aber ich kann nicht herausfinden, wie ich den Datenstrom bekomme.
Irgendwelche Gedanken? Code unten:
Rechnungs Controller
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 eine Lösung gefunden.
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
OK, ich habe es funktioniert. In Schritt 1 wurde daran gearbeitet, dass WickedPDF globale Konfigurationseinstellungen ignoriert, wenn es nicht im Kontext eines Controllers läuft. Schritt 2: Verwenden Sie Tempfile, um die PDF-Ausgabe als Binärmodus-TEMP-Datei zu speichern und anschließend an Carrierwave anzuhängen. Bearbeiteter Originalbeitrag, um die Lösung zu reflektieren. – lascarides
Können Sie mir bitte mehr Details zu Schritt 1 geben? Ich hatte eine alte Version von wkhtmltopdf lokal und exportiert mit render_to_string ganz gut. Auf dem Server habe ich wkhtmltopdf 0.11.0, und render_to_string funktioniert, aber PDF ist nicht lesbar. Upgraden auf 0.11.0 lokal und render_to_string Chokes .. Scheint das gleiche Problem zu sein .. FYI: Ich benutze 'file = StringIO (render_to_string (Optionen)) 'So kann ich die Tempdatei überspringen. Dies ist mit Büroklammer, aber Sie könnten es versuchen, wenn Sie die Idee mögen. –
Froh, dass Sie es gelöst haben. Sie sollten Ihre Lösung als Antwort schreiben und dann Ihre Antwort akzeptieren. Es schadet dir nicht, deine eigene Frage zu beantworten! – sockmonk