draft_forge

Rails engine for exporting HTML or Editor.js JSON to PDF. Can be paired with any front-end or used standalone.

Requires Ruby 3.1 or higher. See CHANGELOG for release notes.

Installation

Copy an initializer and migration into your application:

bin/rails generate draft_forge:install

Attempting to use DraftForge's services before running the generator and migrating will log an error directing you to install and migrate.

Mounting

Expose DraftForge's endpoints by mounting the engine in your application's routes:

# config/routes.rb
Rails.application.routes.draw do
  mount DraftForge::Engine => "/draft_forge"
end

This provides POST /draft_forge to queue a PDF export and GET /draft_forge/:id to check status or download the finished file.

Services

If you prefer not to expose HTTP endpoints, you can queue and fetch exports directly with service objects:

export = DraftForge::CreateExport.call(
  content_json: { blocks: [{ type: 'paragraph', data: { text: 'Hello world' } }] },
  filename: "hello.pdf"
)

DraftForge::FetchExport.call(export.id)
# => { id: 1, status: "queued" }
# Render HTML directly to a PDF without queuing
file = DraftForge::PdfRenderer.call("<p>Hello</p>")
file.close!

Configuration

DraftForge exposes simple configuration hooks for PDF rendering and HTML sanitization. The sanitizer controls which HTML elements (blocks) are allowed, letting you distinguish between editable and non-editable content. By default the sanitizer permits the contenteditable attribute so sanitized markup can be used in live editors.

# config/initializers/draft_forge.rb
DraftForge.configure do |config|
  # Change page size/margins for Grover
  config.pdf_options = { format: 'Letter' }

  # Permit additional HTML elements
  config.sanitizer_config[:elements] += %w[hr]
end

Performance

ExportPdfJob streams generated PDFs to a temporary file before attaching, keeping memory usage low even for very large, 100+ page exports.

Testing

Run the RSpec suite from this directory to verify changes:

bundle exec rspec