2013-02-07 18 views
14

Rails3'te, modellerimden birinin bir PDF biçimini oluşturmak için WickedPDF gem kullanıyorum. Bu iyi çalışıyor: /invoices/123 HTML döndürür, /invoices/123.pdf bir PDF indirir.Carrierwave aracılığıyla ek için WickedPDF'den PDF alınıyor

Fatura modelimde, Fatura durumunu takip etmek için state_machine gemini kullanıyorum. Bir fatura "faturalandırılmamış" durumundan "faturalandırılan" duruma geçtiğinde, fatura PDF'sinin bir kopyasını almak ve CarrierWave'i kullanarak fatura modeline eklemek isterim.

Üç bölümden ayrı olarak çalışıyorum: denetleyici bir PDF görünümü oluşturur, model doğru geçişi yaparken durumu izler ve geri çağrıyı tetikler ve CarrierWave düzgün şekilde kurulur. Ancak, birlikte güzelce oynamasını sağlayan bir zaman geçiriyorum.

Faturanın HTML sürümünü almak istedim, modelden render_to_string'u arayabilirim. Ancak render_to_string, bir PDF ikili dosyası almayı tercih ediyor gibi görünüyor. Bir veri akışı elde edebilirsem, bu verileri bir temp dosyasına yazmak ve yükleyiciye eklemek oldukça kolaydır, ancak veri akışını nasıl alacağımı anlayamıyorum.

Herhangi bir düşünce? Aşağıdaki kodu:

Fatura kontrolörü

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 

GÜNCELLEME bir çözüm bulundu.

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

Tamam, çalışıyorum. Adım 1, bir denetleyici bağlamında çalışmadığında, WickedPDF'nin global yapılandırma ayarlarını yok sayarken çalışmaktadır. Adım 2: PDF çıktısını bir ikili mod tempfile olarak kaydetmek için Tempfile'ı kullanın, ardından bunu Carrierwave'a ekleyin. Çözümü yansıtacak orijinal yayın düzenlendi. – lascarides

+0

Lütfen 1. adımda daha fazla bilgi verebilir misiniz? Yerel olarak wkhtmltopdf eski bir sürümü vardı ve render_to_string ile sadece güzel ihraç ediyordum. Sunucumda wkhtmltopdf 0.11.0 var ve render_to_string çalışıyor ancak PDF okunamıyor .. 0.11.0 lokalize ve render_to_string borazanlarına yükseltildi .. Aynı probleminiz var gibi görünüyor .. FYI: 'file = StringIO kullanıyorum (render_to_string (options)) 'bu yüzden Temp dosyasını atlayabilirim. Bu, ataş ile birlikte, ancak bu fikri beğenirseniz bir deneyebilirsiniz. –

+2

Bunu çözdüğüne sevindim. Çözümünüzü bir cevap olarak yazmalı ve cevabınızı kabul etmelisiniz. Kendi sorunuzu cevaplarken hiçbir zararı yok! – sockmonk

cevap

6

Çözüm:

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 
İlgili konular