In Rails3, sto usando il WickedPDF gem
per eseguire il rendering di un formato PDF di uno dei miei modelli. Funziona perfettamente: /invoices/123
restituisce HTML, /invoices/123.pdf
scarica un PDF.Ottenere PDF da WickedPDF per allegato via Carrierwave
Nel mio modello di fattura, sto utilizzando la gemma state_machine per tenere traccia dello stato della fattura. Quando una fattura passa dallo stato "non completato" a "fatturato", desidero prendere una copia del PDF della fattura e allegarlo al modello di fattura utilizzando CarrierWave.
Ho le tre parti che funzionano separatamente: il controller crea una vista PDF, il modello traccia lo stato e attiva una richiamata quando si effettua la transizione corretta e CarrierWave è impostato correttamente. Comunque, mi sto divertendo un mondo a farli giocare bene insieme.
Se volevo semplicemente prendere la versione HTML della fattura, potrei chiamare render_to_string
dal modello. Ma render_to_string
sembra soffocare sulla ricezione di un file binario PDF. Se riesco a recuperare un flusso di dati, è piuttosto semplice scrivere quei dati in un file temporaneo e collegarli all'uploader, ma non riesco a capire come ottenere il flusso di dati.
Qualche idea? Codice qui sotto:
regolatore Fattura
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 trovato una soluzione.
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, ho funzionato. Il passaggio 1 stava lavorando sul fatto che WickedPDF ignora le impostazioni globali di configurazione quando non è in esecuzione nel contesto di un controller. Passaggio 2: utilizzare Tempfile per salvare l'output PDF come tempfile in modalità binaria, quindi collegarlo a Carrierwave. Post originale modificato per riflettere la soluzione. – lascarides
Potete per favore fornirmi maggiori dettagli sul punto 1? Avevo una vecchia versione di wkhtmltopdf localmente e stavo esportando con render_to_string bene. Sul server ho wkhtmltopdf 0.11.0, e render_to_string funziona ma PDF è illeggibile .. Aggiornato a 0.11.0 localmente e render_to_string indeboli .. Sembra essere lo stesso problema che stai avendo .. FYI: Io uso 'file = StringIO (render_to_string (options)) 'così posso saltare il Tempfile. Questo è con graffetta, ma potresti provare se ti piace l'idea. –
Felice di averlo risolto. Dovresti scrivere la tua soluzione come risposta, e quindi accettare la tua risposta. Nessun danno nel rispondere alla tua stessa domanda! – sockmonk