I’ve tried getting the html from my view with the render_to_string method, but it’s not working. How do I capture the html generated by a view from within a controller?
Also, can anyone suggest a better solution for creating PDFs in Rails? Many thanks for any tips…
I use WKHTMLTOPDF as well, and I created this module (currently stored in lib/pdf_generator.rb) to handle creating PDFs from a given view template in our app:
module PDFGenerator
def generate_pdf_name(attrs)
file_dir = attrs[:file_dir]
file_name_prefix = attrs.fetch(:file_name_prefix, '')
begin
name = "#{file_name_prefix}#{SecureRandom.urlsafe_base64(22)}"
end while File.exists?("#{file_dir}/#{name}.pdf")
name
end
def generate_pdf(attrs)
view_template = attrs[:view_template]
locals = attrs[:locals]
file_dir = attrs[:file_dir]
file_name_prefix = attrs.fetch(:file_name_prefix, '')
wkhtmltopdf_options = attrs.fetch(:wkhtmltopdf_options, {})
html = render_to_string(
partial: view_template,
locals: locals,
layout: false
)
kit = PDFKit.new(html, wkhtmltopdf_options)
css_file_path = "#{Rails.root}/app/assets/stylesheets/pdf.css"
kit.stylesheets << css_file_path
FileUtils.mkdir_p(file_dir)
pdf_name =
generate_pdf_name(file_name_prefix: file_name_prefix, file_dir: file_dir)
file_name = "#{pdf_name}.pdf"
file_path = Rails.root.join("#{file_dir}/#{file_name}").to_s
kit.to_file(file_path)
{ file_name: file_name, file_path: file_path }
end
end
Include the module, then you can use it like this:
And you get back a hash stored in the pdf variable with the file_name and file_path. Obviously you can modify this to your needs.
You could also probably apply extract class a few times on the generate_pdf method, but I liked having the locality of it all in one, albeit larger, method call. It’s already in it’s own module after all. I’m sure there is other cleanup that could be done to this as well. I’m certainly open to suggestions, though this has been working quite well for me for a few months.
I should mention two things… the :full_w_time is a custom time format that I added, so yea, just FYI. And also, my solution doesn’t take Heroku into account at all… I actually prefer to host on DigitalOcean for toy stuff and BlueBox for production apps so I have access to the local file system specifically for things like generating PDF files, etc. Hopefully what I provided can still be useful though. Maybe in the kit.to_file(file_path) call you could save the file to an S3 bucket or something instead of trying to save it to the local file system. Maybe someone with more Heroku/S3 experience can help chime in.