html2pdf-rails 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5c933b1cfb11343837f0b30972a1062ffe7dc3e4d03e089a0734dfea617e320c
4
- data.tar.gz: 20eb371e7da0b2795e2d9eea78487b5e7cad9e7e7f00317613b69fa2428ee660
3
+ metadata.gz: 3651940b4f5e82b4b9016f5ee19bb796445247b2f7f6b47e4f7e61b9bb77c57d
4
+ data.tar.gz: 51f9ab1f57f30e455053a06f37aac4599ea30ff1dcb36b8deff32ee283411456
5
5
  SHA512:
6
- metadata.gz: 121de0d8ceb2c4d40474ae991fa4c286794c67db29d477f7214ca923743afc86acda4fa02313b7b7d31ce81d4bc31694d12f8464a3e3332aafb7f0f6a860eb6f
7
- data.tar.gz: 94b153953fbc58c413140555b499bf4e3967d9c7d857520adef5f85299b39708805f841b9a2744737471eeaaa0a4f4c3d407053c9d7b96614bb6e6a73c6b2bfa
6
+ metadata.gz: 44b1e70af04a620a235a53091b3ab6b6b6b02d556da30e3dccabe6001cdd32566820c72671d14843720cfebf1ab9cc41757cfc090158519a1ad99d4ca5e8d8ba
7
+ data.tar.gz: 1148efd75a6d2ca35bd16259082d9dc301f12bd9bc2979c7b0566d419e74179403af2c7c1742f4d58ac84d15dfa09728d379ad4ce828fe6de6548e5948a5b496
@@ -0,0 +1,30 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [ main ]
6
+ pull_request:
7
+ branches: [ main ]
8
+ workflow_dispatch:
9
+
10
+ jobs:
11
+ test:
12
+ runs-on: ubuntu-latest
13
+
14
+ strategy:
15
+ fail-fast: false
16
+ matrix:
17
+ ruby-version: ['3.2', '3.3', '3.4', '4.0']
18
+
19
+ steps:
20
+ - name: Checkout code
21
+ uses: actions/checkout@v4
22
+
23
+ - name: Set up Ruby ${{ matrix.ruby-version }}
24
+ uses: ruby/setup-ruby@v1
25
+ with:
26
+ ruby-version: ${{ matrix.ruby-version }}
27
+ bundler-cache: true
28
+
29
+ - name: Run tests
30
+ run: bundle exec rspec -fp
data/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ ![CI](https://github.com/SonicGarden/html2pdf-rails/actions/workflows/ci.yml/badge.svg)
2
+
1
3
  # html2pdf-rails
2
4
 
3
5
  PDF generator (from HTML) gem for Ruby on Rails.
@@ -59,6 +61,40 @@ You can get signed url of Cloud Storage if your Cloud Funciton code support it.
59
61
  redirect_to pdf_url
60
62
  ```
61
63
 
64
+ ### Attach PDF to an email (ActionMailer)
65
+
66
+ `render_to_pdf_string` is available in all mailers. It renders a template, converts it to PDF, and returns the PDF binary.
67
+
68
+ ```ruby
69
+ class OrderMailer < ApplicationMailer
70
+ def receipt(order)
71
+ @order = order
72
+ attachments['receipt.pdf'] = render_to_pdf_string
73
+ mail(to: order.user.email)
74
+ end
75
+ end
76
+ ```
77
+
78
+ By default, the template is inferred from `<mailer_name>/<action_name>` and `formats: [:pdf]` is used. So the example above renders `order_mailer/receipt.pdf.erb`. You can override these defaults:
79
+
80
+ ```ruby
81
+ attachments['receipt.pdf'] = render_to_pdf_string(
82
+ template: 'order_mailer/receipt_pdf',
83
+ layout: 'pdf',
84
+ pdf_options: { margin: { top: '30px' } }
85
+ )
86
+ ```
87
+
88
+ ### Generate PDF from arbitrary HTML
89
+
90
+ If you already have an HTML string (for example, in a background job or PORO), use the low-level API:
91
+
92
+ ```ruby
93
+ html = ApplicationController.render(template: 'invoices/show', assigns: { invoice: invoice })
94
+ pdf = Html2Pdf::Rails.generate(html: html, pdf_options: { margin: { top: '30px' } })
95
+ File.binwrite('invoice.pdf', pdf)
96
+ ```
97
+
62
98
  ### Advanced Usage with all available options
63
99
 
64
100
  ```ruby
@@ -130,6 +166,30 @@ Html2Pdf.configure do |config|
130
166
  end
131
167
  ```
132
168
 
169
+ ### `html2pdf_base_tag` in mailers / jobs
170
+
171
+ `html2pdf_base_tag` resolves the base URL in this order (matches Rails `url_for`):
172
+
173
+ 1. Explicit `host:` / `protocol:` argument
174
+ 2. `HTTP_X_ORIGINAL_HOST` request header (host only, for Ngrok-style proxying)
175
+ 3. View-context `url_options[:host]` / `[:protocol]`:
176
+ - In a controller view: `config.action_controller.default_url_options` merged over `request.host` / `request.protocol` (config wins, request as fallback — same behavior as Rails `url_for`)
177
+ - In a mailer view: `config.action_mailer.default_url_options`
178
+ 4. `Rails.application.routes.default_url_options[:host]` / `[:protocol]` (final fallback)
179
+
180
+ Most Rails apps already configure `config.action_mailer.default_url_options` for mailer URL helpers, so no extra setup is usually required:
181
+
182
+ ```ruby
183
+ # config/environments/production.rb
184
+ config.action_mailer.default_url_options = { host: 'example.com', protocol: 'https' }
185
+ ```
186
+
187
+ If you want to override per-call (e.g. multi-tenant), pass arguments:
188
+
189
+ ```erb
190
+ <%= html2pdf_base_tag host: 'tenant.example.com', protocol: 'https' %>
191
+ ```
192
+
133
193
  ## Contributing
134
194
 
135
195
  Bug reports and pull requests are welcome on GitHub at https://github.com/SonicGarden/html2pdf-rails. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
@@ -3,11 +3,64 @@
3
3
  module Html2Pdf
4
4
  module Rails
5
5
  module Helper
6
- def html2pdf_base_tag
7
- # NOTE: for Ngrok
8
- host = request.headers['HTTP_X_ORIGINAL_HOST'] || request.host
9
- base_url = "#{request.protocol}#{host}"
10
- tag.base href: base_url
6
+ # Resolves the base URL in the same order as Rails' `url_for`, with one
7
+ # gem-specific addition (HTTP_X_ORIGINAL_HOST). See `_html2pdf_default_url_options`
8
+ # for the source of `options`.
9
+ def html2pdf_base_tag(host: nil, protocol: nil)
10
+ req = _html2pdf_request
11
+ options = _html2pdf_default_url_options
12
+
13
+ # HTTP_X_ORIGINAL_HOST overrides options because dev tunneling (Ngrok) sets
14
+ # this header to the externally-visible host that puppeteer must reach,
15
+ # which doesn't match request.host or any configured default.
16
+ host ||= req && req.headers['HTTP_X_ORIGINAL_HOST']
17
+ host ||= options[:host]
18
+ if host.blank?
19
+ raise ArgumentError,
20
+ 'html2pdf_base_tag: host is not available. Pass `host:` or configure default_url_options (e.g. config.action_mailer.default_url_options).'
21
+ end
22
+
23
+ # options[:protocol] from controller's url_options is "https://" (with trailing
24
+ # "://" — request.protocol convention), while config and mailer values are
25
+ # bare "https". Normalize.
26
+ protocol ||= options[:protocol]&.to_s&.delete_suffix('://')
27
+ protocol ||= 'https'
28
+
29
+ tag.base href: "#{protocol}://#{host}"
30
+ end
31
+
32
+ private
33
+
34
+ def _html2pdf_request
35
+ respond_to?(:request) ? request : nil
36
+ end
37
+
38
+ # Mirrors how Rails' `url_for` resolves URL options, so this helper produces
39
+ # the same host/protocol as `url_for` would in the same context.
40
+ #
41
+ # `view.url_options` delegates to `controller.url_options`:
42
+ # https://github.com/rails/rails/blob/v8.1.2/actionview/lib/action_view/routing_url_for.rb#L124
43
+ #
44
+ # In a controller this returns
45
+ # `{ host: request.host, protocol: request.protocol, ... }.merge!(super)`:
46
+ # https://github.com/rails/rails/blob/v8.1.2/actionpack/lib/action_controller/metal/url_for.rb#L37
47
+ # `merge!` lets class-level `default_url_options` win over request info.
48
+ # In a mailer it returns the class-level `default_url_options` directly
49
+ # (no request to merge in).
50
+ #
51
+ # `RouteSet#url_for` then does `default_url_options.merge(options)`, so
52
+ # routes' default is the base under everything else. We replicate that here:
53
+ # https://github.com/rails/rails/blob/v8.1.2/actionpack/lib/action_dispatch/routing/route_set.rb#L856
54
+ #
55
+ # Note: `config.action_mailer.default_url_options` and
56
+ # `config.action_controller.default_url_options` populate the *class*
57
+ # `default_url_options`, NOT `Rails.application.routes.default_url_options` —
58
+ # they are three separate hashes. Reading only the routes hash would miss the
59
+ # typical mailer setup.
60
+ def _html2pdf_default_url_options
61
+ routes_options = ::Rails.application&.routes&.default_url_options || {}
62
+ context_options = respond_to?(:url_options) ? url_options : {}
63
+ routes_options.merge(context_options)
11
64
  end
12
65
  end
13
66
  end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Html2Pdf
4
+ module Rails
5
+ module MailerRendering
6
+ def render_to_pdf_string(template: nil, layout: false, formats: [:pdf], handlers: nil, pdf_options: {})
7
+ # When :template is omitted, Rails resolves the template from `_prefixes`
8
+ # (= [mailer_name]) and `action_name` via `_process_render_template_options`:
9
+ # https://github.com/rails/rails/blob/v8.1.2/actionview/lib/action_view/rendering.rb#L177
10
+ render_opts = { template: template, layout: layout, formats: formats, handlers: handlers }.compact
11
+ html = render_to_string(**render_opts)
12
+ Html2Pdf::Rails.generate(html: html, pdf_options: pdf_options)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'rails'
3
4
  require 'html2pdf/rails/rendering'
5
+ require 'html2pdf/rails/mailer_rendering'
4
6
  require 'html2pdf/rails/helper'
5
7
 
6
8
  module Html2Pdf
@@ -10,6 +12,10 @@ module Html2Pdf
10
12
  ActionController::Base.prepend Rendering
11
13
  end
12
14
 
15
+ ActiveSupport.on_load(:action_mailer) do
16
+ ActionMailer::Base.include MailerRendering
17
+ end
18
+
13
19
  ActiveSupport.on_load(:action_view) do
14
20
  ActionView::Base.include Helper
15
21
  end
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'retryable'
4
- require 'html2pdf/rails/client'
5
-
6
3
  module Html2Pdf
7
4
  module Rails
8
5
  module Rendering
@@ -28,9 +25,15 @@ module Html2Pdf
28
25
 
29
26
  def _html2_pdf_render_pdf_and_get_url(pdf_name, options = {})
30
27
  options = _html2pdf_default_options(pdf_name, options)
31
- options[:put_to_storage] = true
32
- json = JSON.parse(_html2pdf_make_pdf(options))
33
- json['url']
28
+ html = _html2pdf_render_html(options)
29
+ response = Html2Pdf::Rails.generate(
30
+ html: html,
31
+ pdf_options: options[:pdf_options],
32
+ put_to_storage: true,
33
+ file_name: options[:file_name],
34
+ disposition: options[:disposition]
35
+ )
36
+ JSON.parse(response)['url']
34
37
  end
35
38
 
36
39
  def _html2pdf_make_and_send_pdf(pdf_name, options = {})
@@ -40,24 +43,15 @@ module Html2Pdf
40
43
  render_opts = options.slice(:template, :layout, :formats, :handlers)
41
44
  render(render_opts.merge({ content_type: 'text/html' }))
42
45
  else
43
- pdf_content = _html2pdf_make_pdf(options)
46
+ html = _html2pdf_render_html(options)
47
+ pdf_content = Html2Pdf::Rails.generate(html: html, pdf_options: options[:pdf_options])
44
48
  send_data(pdf_content, filename: options[:file_name], type: 'application/pdf', disposition: options[:disposition])
45
49
  end
46
50
  end
47
51
 
48
- def _html2pdf_make_pdf(options = {})
52
+ def _html2pdf_render_html(options)
49
53
  render_opts = options.slice(:template, :layout, :formats, :handlers)
50
- html = render_to_string(**render_opts)
51
-
52
- Retryable.retryable(tries: 3, on: Html2Pdf::Rails::ServiceUnavailableError) do
53
- Client.post(
54
- html: html,
55
- put_to_storage: options[:put_to_storage],
56
- file_name: options[:file_name],
57
- disposition: options[:disposition],
58
- pdf_options: options[:pdf_options]
59
- )
60
- end
54
+ render_to_string(**render_opts)
61
55
  end
62
56
  end
63
57
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Html2Pdf
4
4
  module Rails
5
- VERSION = '0.5.0'
5
+ VERSION = '0.7.0'
6
6
  end
7
7
  end
@@ -1,12 +1,17 @@
1
- require 'active_support/configurable'
1
+ require 'retryable'
2
2
  require 'html2pdf/rails/version'
3
+ require 'html2pdf/rails/errors'
4
+ require 'html2pdf/rails/client'
3
5
  require 'html2pdf/rails/railtie'
4
6
 
5
7
  module Html2Pdf
6
8
  class Config
7
- include ActiveSupport::Configurable
8
- config_accessor :endpoint
9
- config_accessor :app
9
+ attr_accessor :endpoint, :app
10
+
11
+ def initialize
12
+ @endpoint = nil
13
+ @app = nil
14
+ end
10
15
  end
11
16
 
12
17
  class << self
@@ -18,4 +23,18 @@ module Html2Pdf
18
23
  @config ||= Config.new
19
24
  end
20
25
  end
26
+
27
+ module Rails
28
+ def self.generate(html:, pdf_options: {}, put_to_storage: false, file_name: nil, disposition: nil)
29
+ Retryable.retryable(tries: 3, on: ServiceUnavailableError) do
30
+ Client.post(
31
+ html: html,
32
+ pdf_options: pdf_options,
33
+ put_to_storage: put_to_storage,
34
+ file_name: file_name,
35
+ disposition: disposition
36
+ )
37
+ end
38
+ end
39
+ end
21
40
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: html2pdf-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - aki77
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2025-04-15 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: rails
@@ -87,10 +86,10 @@ executables: []
87
86
  extensions: []
88
87
  extra_rdoc_files: []
89
88
  files:
89
+ - ".github/workflows/ci.yml"
90
90
  - ".gitignore"
91
91
  - ".rspec"
92
92
  - ".rubocop.yml"
93
- - ".travis.yml"
94
93
  - CODE_OF_CONDUCT.md
95
94
  - Gemfile
96
95
  - LICENSE.txt
@@ -103,6 +102,7 @@ files:
103
102
  - lib/html2pdf/rails/client.rb
104
103
  - lib/html2pdf/rails/errors.rb
105
104
  - lib/html2pdf/rails/helper.rb
105
+ - lib/html2pdf/rails/mailer_rendering.rb
106
106
  - lib/html2pdf/rails/railtie.rb
107
107
  - lib/html2pdf/rails/rendering.rb
108
108
  - lib/html2pdf/rails/version.rb
@@ -110,7 +110,6 @@ homepage: https://github.com/SonicGarden/html2pdf-rails
110
110
  licenses:
111
111
  - MIT
112
112
  metadata: {}
113
- post_install_message:
114
113
  rdoc_options: []
115
114
  require_paths:
116
115
  - lib
@@ -125,8 +124,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
125
124
  - !ruby/object:Gem::Version
126
125
  version: '0'
127
126
  requirements: []
128
- rubygems_version: 3.5.16
129
- signing_key:
127
+ rubygems_version: 4.0.3
130
128
  specification_version: 4
131
129
  summary: PDF generator (from HTML) gem for Ruby on Rails
132
130
  test_files: []
data/.travis.yml DELETED
@@ -1,7 +0,0 @@
1
- ---
2
- sudo: false
3
- language: ruby
4
- cache: bundler
5
- rvm:
6
- - 2.5.3
7
- before_install: gem install bundler -v 1.16.6