The Ruby On Rails Wiki lists a couple of libraries that facilitate PDF generation in Rails. I need to print out address labels (in letter f
I've used flying saucer for pdf generation from html. It's a java library but you can use the Ruby-Java Bridge gem to access it in your rails app. It's css 2.1 compliant and has a few additions from css3 to allow some extra control over paging. I'd recommend it as it doesn't require you to put 'pdf code' in your html, you can use the same views and partials to display to the browser as you do to generate pdfs.
Flying Saucer: https://github.com/flyingsaucerproject/flyingsaucer
Ruby Java Bridge: http://rjb.rubyforge.org/
I use this module code to generate the pdfs
require 'rubygems'
require 'rjb'
module Html2Pdf
def self.included(controller)
controller.send :helper_method, :create_pdf
end
def create_pdf(options = {})
itext = "#{RAILS_ROOT}/lib/html2pdf/jars/iText-2.0.8.jar"
core_renderer = "#{RAILS_ROOT}/lib/html2pdf/jars/core-renderer.jar"
xerces = "#{RAILS_ROOT}/lib/html2pdf/jars/xml-apis-xerces-2.9.1.jar"
joinchar = (RUBY_PLATFORM.include? 'mswin') ? ';' : ':'
classpath = [itext, core_renderer, xerces].join(joinchar)
Rjb::load(classpath, jvmargs=['-Djava.awt.headless=true'])
if options[:htmlstring].nil?
options[:layout] ||= false
options[:template] ||= File.join(controller_path,action_name+".pdf.erb")
html_string = render_to_string(:template => options[:template], :layout => options[:layout])
else
html_string = options[:htmlstring]
end
# Make all paths relative, on disk paths...
html_string.gsub!(".com:/",".com/") # strip out bad attachment_fu URLs
html_string.gsub!( /src=["']+([^:]+?)["']/i ) { |m| "src=\"file:///#{RAILS_ROOT}/public/" + $1 + '"' } # re-route absolute paths
html_string.gsub!( /url\(["']+([^:]+?)["']/i ) { |m| "url\(\"file:///#{RAILS_ROOT}/public/" + $1 + '"' } # re-route absolute paths
# Remove asset ids on images with a regex // tbh i can't remember what this line is for but i'm sure it did something awesome
html_string.gsub!( /src=["'](\S+\?\d*)["']/i ) { |m| 'src="' + $1.split('?').first + '"' }
filename = "#{RAILS_ROOT}/public/pdfs/"+options[:filename]+".pdf"
fileOutputStream = Rjb::import('java.io.FileOutputStream')
iTextRenderer = Rjb::import('org.xhtmlrenderer.pdf.ITextRenderer')
renderer = iTextRenderer.new
renderer.setDocumentFromString(html_string)
os = fileOutputStream.new(filename)
renderer.layout()
renderer.createPDF(os)
os.close()
end
end
Calling it with code like this:
def generate_pdf
htmlsrc = render_to_string(:partial => 'invoice', :layout => false)
rnd = Time.now.to_s(:datentime).gsub!(/[\/ \.:]/,'')
filename = "docstore/tmp_#{rnd}"
create_pdf(:htmlstring => htmlsrc, :filename => filename)
contents = open("#{RAILS_ROOT}/public/pdfs/#{filename}.pdf", "rb") { |io| io.read }
File.delete("#{RAILS_ROOT}/public/pdfs/#{filename}.pdf")
respond_to do | wants |
wants.html { render :text => contents, :content_type => 'application/pdf' }
end
end