Furqan Asghar
Furqan Asghar

Reputation: 3860

wicked_pdf multi page document

I have a scenario where i need to generate a multipage pdf based on an array of objects.

Following is my models:

# Member has_many certificates

class Member < ActiveRecord::Base

  has_many :certificates, dependent: :destroy

  before_save :set_expiry

  def self.delete_expired
    where(expire_at: Date.today).destroy_all
  end

  private
    def set_expiry
      self.expire_at = 15.days.from_now
    end
end

# certificate belongs_to member
class Certificate < ActiveRecord::Base
  belongs_to :member
  belongs_to :certificate_type
  belongs_to :company

  def company_name
    company.name
  end

  def page_orientation
    company_name == 'CompanyA' ? 'Landscape' : 'Portrait'
  end

  def page_height
    company_name == 'CompanyA' ? '10.5in' : '11in'
  end

  def page_width
    company_name == 'CompanyA' ? '7in' : '8.5in'
  end
end

# each type can have many certificates
class CertificateType < ActiveRecord::Base
  has_many :certificates
end

The user flow is something like following:

I have a custom form where i'm creating certificate objects (checkbox selection) and then submitting the form. The controller receives a hash of certificate objects. I have to loop through all the objects one by one to create the certificate for it's associated member. The problem is that each certificate has it's own template and some custom page layout settings like orientation, width and height. I want to generate one single pdf file with multiple pages where each page is a single certificate. I'm stuck at where and how should i pass the page layout settings for each individual certificate. I tried render_to_string in my controller and tried to set page layout options there but it doesn't seem to work. I need some suggestion or pointers here.

Upvotes: 2

Views: 3270

Answers (3)

Rafael_Mancini
Rafael_Mancini

Reputation: 236

In my case I wanted to generate multiple PDFs in a background job and save the final merged file as an attachment in my model. So I did it like this:

def generate_and_send
 begin
  final_pdf = pdf_from_html.to_pdf
  FileUtils.mkdir_p(File.dirname(pdf_path)) unless Dir.exists?(File.dirname(pdf_path))
  File.open(pdf_path, 'wb') do |file|
    file << final_pdf
  end
  @object.attachment = File.open pdf_path
  @object.save
 rescue => e
  notifiy_status('error')
 end

And my pdf generator and merger was set-up like this

   def pdf_from_html
    #Will generate each page in separate to prevent memory overflow
    #Then joins the pages
    final_pdf = CombinePDF.new
    pages = @pages_to_print.select{ |k, v| v == '1'}.keys
    pages.each do |page|
      page_html = render("#{page}") #This method defines the layout based on the page
      pdf_from_page = WickedPdf.new.pdf_from_string(page_html)
      final_pdf << CombinePDF.parse(pdf_from_page, allow_optional_content: true)
    end
    final_pdf
  end

Tips: Remember to use the method .to_pdf

Upvotes: 1

Myst
Myst

Reputation: 19221

Building on @fdisk 's answer, but using the Ruby native combine_pdf gem... you could try:

require 'combine_pdf'

merged_certificates = CombinePDF.new

@member.certificates.each do |certificate|
  pdf_data = WickedPdf.new.pdf_from_string(render_to_string(something, layout: some_layout))
  merged_certificates  << CombinePDF.parse(pdf_data)
end

send_data merged_certificates.to_pdf, filename: 'mypdf.pdf' #...

Upvotes: 5

fdisk
fdisk

Reputation: 438

Since this is an option, I would recommend installing poppler-utils via your distro's package manager (yum, apt-get, dnf, etc.). After that, save each certificate as a Tempfile:

require 'shellwords'

certificates = @member.certificates.map do |certificate|
  Tempfile.open(["cert", ".pdf"]) { |file| file << WickedPdf.new.pdf_from_string(render_to_string(something, layout: some_layout)) }
end

paths = certificates.map { |cert| cert.path.shellescape }

@final_pdf = Tempfile.new(["cert", ".pdf"])
@final_pdf.close
%x[pdfunite #{paths} #{@final_pdf.path.shellescape}]

That @final_pdf object should contain the merged individual certificates. I've also made a simple gem to handle these cases, but it may have a bit of extra overhead you're not looking for (it's designed to create combined PDF files with nested bookmarks).

Upvotes: 0

Related Questions