soli-pdf

Soli::PDF

The whole public API fits in one module: two render methods, a warnings reader, a binary setter, and four error classes.

require 'soli/pdf'

pdf = Soli::PDF.render(template: template, data: data, title: 'Invoice F-42')
Soli::PDF.render_to_file('invoice.pdf', template: template, data: data)
Soli::PDF.last_warnings         # => ["unresolved placeholder: ${invoice.po}"]
Soli::PDF.binary_path = '/opt/render-pdf/render_pdf'

#Soli::PDF.render

Soli::PDF.render(template:, data: nil, invoice: nil, xml: nil, **options) # => String (binary)

Renders a PDF and returns its bytes as a binary String (encoding ASCII-8BIT), ready for File.binwrite, send_data or an upload.

ArgumentTypeMeaning
template:Hash, Array or StringThe layout template. A Hash or Array is serialised with JSON.generate. A String is passed through as JSON text, not as a file path.
data:Hash, Array or StringThe data document the ${...} placeholders read from. It can be wrapped as { 'data' => {...} } or given bare.
invoice:Hash or StringA typed invoice, used instead of data:. The renderer computes the totals and VAT breakdown and embeds a generated EN 16931 XML. See Factur-X.
xml:StringA Factur-X CII XML document to embed, used with data:. The output becomes PDF/A-3b.
**optionstitle, author, subject, profile, password, owner_password, stationery, attachments, fonts, images. See Render options.

Argument rules, checked before anything runs. Each one raises ArgumentError:

  • exactly one of data: and invoice: must be given (give either data: or invoice:);
  • xml: cannot be combined with invoice:, which generates its own XML;
  • an option outside the list above is refused (unknown option(s): …).
# A template kept as a JSON file can be passed as a String, without parsing it.
pdf = Soli::PDF.render(template: File.read('quote.template.json'), data: quote.to_pdf_data)

# Symbol keys are fine too: JSON.generate turns them into strings.
pdf = Soli::PDF.render(template: template, data: { invoice: { number: 'F-42' } })

On success, render also replaces Soli::PDF.last_warnings. On failure it raises; see Errors & warnings.

#Soli::PDF.render_to_file

Soli::PDF.render_to_file(path, **args) # => path

Calls render(**args) and writes the bytes to path with File.binwrite. Returns path. It takes the same keyword arguments as render.

Soli::PDF.render_to_file(Rails.root.join('tmp', "invoice-#{invoice.id}.pdf"),
                         template: TEMPLATE, data: invoice.to_pdf_data)

#Soli::PDF.last_warnings

Soli::PDF.last_warnings # => Array<String>

The warnings the renderer printed during the last successful render: placeholders with no value, images that could not be loaded, characters that no loaded font covers, invalid barcode data, and so on. It is empty when there were none, and before the first render.

pdf = Soli::PDF.render(template: template, data: data)
Rails.logger.warn("PDF: #{Soli::PDF.last_warnings.join('; ')}") if Soli::PDF.last_warnings.any?

Warning last_warnings is stored on the module, so all threads share it. In a threaded server (Puma), read it right after your own render call and treat it as best-effort: another thread's render can replace it in between.

#Soli::PDF.binary_path=

Soli::PDF.binary_path = '/opt/render-pdf/render_pdf'
Soli::PDF.binary_path = nil   # back to SOLI_PDF_BIN or the downloaded copy

Uses this executable instead of the downloaded one. It takes precedence over the SOLI_PDF_BIN environment variable. The path must point to an executable file. If it doesn't, the next render raises Soli::PDF::BinaryNotFound. See The render_pdf binary.

In a Rails app, set it in an initializer:

# config/initializers/soli_pdf.rb
Soli::PDF.binary_path = ENV['RENDER_PDF_PATH'] if ENV['RENDER_PDF_PATH']

#Soli::PDF::Binary

The class that locates the executable. You rarely need it directly, but it is handy for health checks and build steps.

MethodReturns
Binary.pathAbsolute path of the executable. Downloads it first if needed.
Binary.fonts_dirThe fonts/ directory next to the executable, or nil.
Binary.install_dirWhere the downloaded copy lives: ~/.cache/soli-pdf/<BINARY_VERSION>/render-pdf-<os>-<arch>.
Binary.artifactThe release asset name for this machine, for example render-pdf-linux-amd64.
# Fail the deploy early rather than the first customer's download.
Soli::PDF::Binary.path

#Constants

ConstantValueMeaning
Soli::PDF::VERSION"0.1.0"The gem's version.
Soli::PDF::BINARY_VERSION"2.9.0"The Soli release whose render_pdf assets the gem downloads.

#Errors

All errors inherit from Soli::PDF::Error, which inherits from StandardError:

ClassRaised when
Soli::PDF::BinaryNotFoundThe platform is unsupported, or a configured path is not executable.
Soli::PDF::DownloadErrorThe release asset could not be fetched or unpacked, or its SHA-256 did not match.
Soli::PDF::RenderErrorrender_pdf exited with an error. It has #stderr (the renderer's message) and #status (a Process::Status).

Errors & warnings shows the messages and how to handle each one.