Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,45 @@
### Unreleased

* Replace controller methods with a Rails renderer

This provides a much cleaner and better named Rails integration. You can pass options directly into the `render` method which will render the PDF or screenshot and pass it along to `send_data` for you.

Before:

```ruby
class PdfsController < ApplicationController
def show
respond_to do |format|
format.pdf {
pdf = render_pdf()
send_data pdf, disposition: :inline, filename: "example.pdf"
}
format.png {
screenshot = render_screenshot()
send_data screenshot, disposition: :inline, filename: "example.png"
}
end
end
end
```

After:

```ruby
class PdfsController < ApplicationController
def show
respond_to do |format|
format.pdf { render ferrum_pdf: {}, disposition: :inline, filename: "example.pdf" }
format.png { render ferrum_screenshot: {}, disposition: :inline, filename: "example.png" }
end
end
end
Comment on lines +29 to +36
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So good!

```



* [Breaking] Remove assets helper config option. This will always be included by default.

### 1.0.0

* No changes
Expand Down
41 changes: 20 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ Inspired by [Grover](https://github.com/Studiosity/grover), but without the Node

## Installation

First, make sure Chrome is installed.

Run the following or add the gem to your Gemfile:
First, make sure Chrome is installed. Then run the following or add the gem to your Gemfile:

```ruby
bundle add "ferrum_pdf"
Expand All @@ -22,35 +20,35 @@ You can use FerrumPdf to render [PDFs](#-pdfs) and [Screenshots](#-screenshots)

There are two ways to render PDFs:

* [`render ferrum_pdf: {}` in Rails](#render-pdfs-from-rails-controllers)
* [FerrumPdf.render_pdf](#render-pdfs)
* [render_pdf in Rails](#render-pdfs-from-rails-controllers)

#### Render PDFs from Rails controllers

Use the `render_pdf` helper in Rails controllers to render a PDF from the current action.
Use the `ferrum_pdf` renderer in Rails controllers to render a PDF from the current action.

```ruby
def show
respond_to do |format|
format.html
format.pdf {
pdf = render_pdf()
send_data pdf, disposition: :inline, filename: "example.pdf"
}
format.pdf { render ferrum_pdf: {}, disposition: :inline, filename: "example.pdf" }
end
end
```

You can also customize which template is rendered. This will render the template to string with `render_to_string` in Rails, then pass it along to Chrome. For example, you can add headers and footers using `pdf_options` and use a specific layout:

```ruby
render_pdf(
layout: "pdf,
render ferrum_pdf: {
pdf_options: {
display_header_footer: true,
header_template: FerrumPdf::DEFAULT_HEADER_TEMPLATE,
footer_template: FerrumPdf::DEFAULT_FOOTER_TEMPLATE
}
},
layout: "pdf",
template: "pdf",
disposition: :inline,
filename: "example.pdf"
)
```

Expand Down Expand Up @@ -112,29 +110,26 @@ See [Chrome DevTools Protocol docs](https://chromedevtools.github.io/devtools-pr

There are two ways to render Screenshots:

* [`render ferrum_screenshot: {}` in Rails](#render-screenshots-from-rails-controllers)
* [FerrumPdf.render_screenshot](#render-screenshots)
* [render_screenshot in Rails](#render-screenshots-from-rails-controllers)

#### Render Screenshots from Rails controllers

Use the `render_screenshot` helper in Rails controllers to render a PDF from the current action.
Use the `ferrum_screenshot` renderer in Rails controllers to render a PDF from the current action.

```ruby
def show
respond_to do |format|
format.html
format.png {
screenshot = render_screenshot()
send_data screenshot, disposition: :inline, filename: "example.png"
}
format.png { render ferrum_screenshot: {}, disposition: :inline, filename: "example.png" }
end
end
```

You can also customize which template is rendered. This will render the template to string with `render_to_string` in Rails, then pass it along to Chrome.

```ruby
render_screenshot(
render ferrum_screenshot: {
screenshot_options: {
format: "png" # or "jpeg"
quality: nil # Integer 0-100 works for jpeg only
Expand All @@ -143,8 +138,12 @@ render_screenshot(
area: nil # Hash area for screenshot, optional. {x: 0, y: 0, width: 100, height: 100}
scale: nil # Float zoom in/out
background_color: nil # Ferrum::RGBA.new(0, 0, 0, 0.0)
}
)
},
layout: "example",
template: "example"
disposition: :inline,
filename: "example.png"
}
```

See [Ferrum screenshot docs](https://github.com/rubycdp/ferrum?tab=readme-ov-file#screenshotoptions--string--integer) for the full set of options.
Expand Down
4 changes: 1 addition & 3 deletions lib/ferrum_pdf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,9 @@ module FerrumPdf
HTML

autoload :AssetsHelper, "ferrum_pdf/assets_helper"
autoload :Controller, "ferrum_pdf/controller"
autoload :HTMLPreprocessor, "ferrum_pdf/html_preprocessor"

mattr_accessor :browser_mutex, default: Mutex.new
mattr_accessor :include_assets_helper_module, default: true
mattr_accessor :include_controller_module, default: true
mattr_accessor :config, default: ActiveSupport::OrderedOptions.new.merge(
window_size: [ 1920, 1080 ]
)
Expand Down Expand Up @@ -90,6 +87,7 @@ def render_screenshot(screenshot_options: {}, **load_page_args)
#
def load_page(url: nil, html: nil, base_url: nil, authorize: nil, wait_for_idle_options: nil, browser: nil, retries: 1)
try = 0
wait_for_idle_options ||= {}

with_browser(browser) do |browser|
# Closes page automatically after block finishes
Expand Down
70 changes: 35 additions & 35 deletions lib/ferrum_pdf/assets_helper.rb
Original file line number Diff line number Diff line change
@@ -1,53 +1,53 @@
module FerrumPdf
module AssetsHelper
class BaseAsset
def initialize(asset)
@asset = asset
end
class BaseAsset
def initialize(asset)
@asset = asset
end
end

class PropshaftAsset < BaseAsset
def content_type
@asset.content_type.to_s
end
class PropshaftAsset < BaseAsset
def content_type
@asset.content_type.to_s
end

def content
@asset.content
end
def content
@asset.content
end
end

class SprocketsAsset < BaseAsset
def content_type
@asset.content_type
end
class SprocketsAsset < BaseAsset
def content_type
@asset.content_type
end

def content
@asset.source
end
def content
@asset.source
end
end

class AssetFinder
class << self
def find(path)
if Rails.application.assets.respond_to?(:load_path)
propshaft_asset(path)
elsif Rails.application.assets.respond_to?(:find_asset)
sprockets_asset(path)
else
nil
end
class AssetFinder
class << self
def find(path)
if Rails.application.assets.respond_to?(:load_path)
propshaft_asset(path)
elsif Rails.application.assets.respond_to?(:find_asset)
sprockets_asset(path)
else
nil
end
end

def propshaft_asset(path)
(asset = Rails.application.assets.load_path.find(path)) ? PropshaftAsset.new(asset) : nil
end
def propshaft_asset(path)
(asset = Rails.application.assets.load_path.find(path)) ? PropshaftAsset.new(asset) : nil
end

def sprockets_asset(path)
(asset = Rails.application.assets.find_asset(path)) ? SprocketsAsset.new(asset) : nil
end
def sprockets_asset(path)
(asset = Rails.application.assets.find_asset(path)) ? SprocketsAsset.new(asset) : nil
end
end
end

module AssetsHelper
def ferrum_pdf_inline_stylesheet(path)
(asset = AssetFinder.find(path)) ? "<style>#{asset.content}</style>".html_safe : nil
end
Expand Down
27 changes: 0 additions & 27 deletions lib/ferrum_pdf/controller.rb

This file was deleted.

20 changes: 18 additions & 2 deletions lib/ferrum_pdf/railtie.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,29 @@ module FerrumPdf
class Railtie < ::Rails::Railtie
initializer "ferrum_pdf.assets_helper" do
ActiveSupport.on_load(:action_view) do
include FerrumPdf::AssetsHelper if FerrumPdf.include_assets_helper_module
include FerrumPdf::AssetsHelper
end
end

initializer "ferrum_pdf.controller" do
ActiveSupport.on_load(:action_controller) do
include FerrumPdf::Controller if FerrumPdf.include_controller_module
# render ferrum_pdf: { pdf options }, template: "whatever", disposition: :inline, filename: "example.pdf"
ActionController.add_renderer :ferrum_pdf do |pdf_options, options|
send_data_options = options.extract!(:disposition, :filename, :status)
url = pdf_options.delete(:url)
html = render_to_string(**options.with_defaults(formats: [ :html ])) if url.blank?
pdf = FerrumPdf.render_pdf(html: html, base_url: request.base_url, url: url, pdf_options: pdf_options)
send_data(pdf, **send_data_options.with_defaults(type: :pdf))
Comment on lines +13 to +17
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It took me some time to figure this out, but it really is pretty simple. Nice work.

end

# render ferrum_pdf: { pdf options }, template: "whatever", disposition: :inline, filename: "example.png"
ActionController.add_renderer :ferrum_screenshot do |screenshot_options, options|
send_data_options = options.extract!(:disposition, :filename, :status)
url = screenshot_options.delete(:url)
html = render_to_string(**options.with_defaults(formats: [ :html ])) if url.blank?
screenshot = FerrumPdf.render_screenshot(url: url, html: html, base_url: request.base_url, screenshot_options: screenshot_options)
send_data(screenshot, **send_data_options.with_defaults(type: screenshot_options.fetch(:format, :png)))
end
end
end
end
Expand Down
26 changes: 7 additions & 19 deletions test/dummy/app/controllers/pdfs_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,22 @@ def show
respond_to do |format|
format.html
format.pdf {
pdf = render_pdf(
layout: "pdf",
pdf_options: {
render ferrum_pdf: {
display_header_footer: true,
header_template: FerrumPdf::DEFAULT_HEADER_TEMPLATE,
footer_template: FerrumPdf::DEFAULT_FOOTER_TEMPLATE
}
) do |browser, page|
Copy link
Owner Author

@excid3 excid3 Jul 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This block is still possible, but only with FerrumPdf.render_pdf() calls directly.

Rails.logger.debug "FerrumPdf Chrome PID: #{browser.process.pid}"
end
send_data pdf, disposition: :inline, filename: "example.pdf"
},
disposition: :inline,
filename: "example.pdf"
}
format.png { send_data render_screenshot, disposition: :inline, filename: "example.png" }
format.png { render ferrum_screenshot: {}, disposition: :inline, filename: "example.png" }
end
end

def url
respond_to do |format|
format.pdf {
pdf = FerrumPdf.render_pdf(url: params[:url]) do |browser, page|
Rails.logger.debug "FerrumPdf Chrome PID: #{browser.process.pid}"
end
send_data pdf, disposition: :inline, filename: "example.pdf"
}
format.png {
screenshot = FerrumPdf.render_screenshot(url: params[:url], screenshot_options: { full: params[:full] })
send_data screenshot, disposition: :inline, filename: "example.png"
}
format.pdf { render ferrum_pdf: { url: params[:url] }, disposition: :inline, filename: "example.pdf" }
format.png { render ferrum_screenshot: { url: params[:url], full: params[:full] }, disposition: :inline, filename: "example.png" }
end
end
end
2 changes: 1 addition & 1 deletion test/dummy/app/views/layouts/pdf.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= content_for(:title) || "Dummy" %></title>
<title><%= content_for(:title) || "Dummy" %> PDF</title>

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css">
<%= stylesheet_link_tag "print" %>
Expand Down