在 ruby 和 rails 中生成 pdf 的方法有很多种。您可能已经熟悉 html 和 css,因此我们将使用 pdfkit 通过标准 rails 视图和样式代码中的 html 生成 pdf 文件。
在内部,PDFKit 使用 wkhtmltopdf(WebKit HTML 到 PDF),这是一个引擎,它将采用 HTML 和 CSS,使用 WebKit 渲染它,并将其输出为高质量的 PDF。
首先,请在您的计算机上安装 wkhtmltopdf。您可以下载二进制文件或从 Mac 上的 Brew 或您首选的 Linux 存储库进行安装。
您还需要安装 pdfkit gem,然后运行以下 Ruby 代码来生成包含文本“Hello Envato!”的 PDF
require "pdfkit"
kit = PDFKit.new(<<-HTML)
<p>Hello Envato!</p>
HTML
kit.to_file("hello.pdf")
您应该有一个名为 hello.pdf 的新文件,其文本位于顶部。
立即学习“前端免费学习笔记(深入)”;

PDFKit 还允许您从 URL 生成 PDF。如果您想从 Google 主页生成 PDF,您可以运行:
require "pdfkit"
PDFKit.new('https://www.google.com', :page_size => 'A3').to_file('google.pdf')
如您所见,我指定了 page_size — 默认情况下使用 A4。您可以在此处查看完整的选项列表。

之前我提到过我们将使用 HTML 和 CSS 生成 PDF 文件。在此示例中,我添加了一些 CSS 来设置示例发票的 HTML 样式,如您所见:
require "pdfkit"
kit = PDFKit.new(<<-HTML)
<style>
* {
color: grey;
}
h1 {
text-align: center;
color: black;
margin-bottom: 100px;
}
.notes {
margin-top: 100px;
}
table {
width: 100%;
}
th {
text-align: left;
color: black;
padding-bottom: 15px;
}
</style>
<h1>Envato Invoice</h1>
<table>
<thead>
<tr>
<th>Description</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr>
<td>Monthly Subscription to Tuts+</td>
<td>$15</td>
</tr>
</tbody>
</table>
<div class="notes">
<p><strong>Notes:</strong> This invoice was paid on the 23rd of March 2016 using your credit card ending on 1234.</p>
</div>
HTML
kit.to_file("envato_invoice.pdf")
如果运行此脚本,将生成文件envato_invoice.pdf。这张照片显示了样本发票的结果:

如您所见,如果您已经熟悉 HTML 和 CSS,则 PDFKit 非常易于使用。您可以根据需要继续自定义此文档或设计其样式。
现在让我们看看如何在 Rails 应用程序上下文中使用 PDFKit,以便我们可以使用模型中的数据动态生成 PDF 文件。在本节中,我们将构建一个简单的 Rails 应用程序来动态生成之前的“Envato Invoice”。首先创建一个新的 Rails 应用程序并添加三个模型:
$ rails new envato_invoices $ cd envato_invoices $ rails generate model invoice date:date client notes $ rails generate model line_item description price:float invoice:references $ rake db:migrate
现在,我们必须向数据库添加一些示例数据。将此代码片段添加到 db/seeds.rb。
line_items = LineItem.create([
{ description: 'Tuts+ Subscription April 2016', price: 15.0 },
{ description: 'Ruby eBook', price: 9.90} ])
Invoice.create(
client: 'Pedro Alonso',
total: 24.90,
line_items: line_items,
date: Date.new(2016, 4, 1))
在终端中运行 rake db:seed 将示例发票添加到数据库中。
我们还对在应用程序中生成发票列表和一张发票的详细信息感兴趣,因此使用 Rails 生成器,运行 railsgeneratecontrollerInvoicesindexshow 来创建控制器和视图。
app/controllers/invoices_controller.rb
class InvoicesController < ApplicationController
def index
@invoices = Invoice.all
end
def show
@invoice = Invoice.find(params[:id])
end
end
app/views/invoices/index.html.erb
<h1>Invoices</h1>
<ul>
<% @invoices.each do |invoice| %>
<li>
<%= link_to "#{invoice.id} - #{invoice.client} - #{invoice.date.strftime("%B %d, %Y")} ", invoice_path(invoice) %>
</li>
<% end %>
</ul>
我们需要修改rails路由以默认重定向到InvoicesController,因此编辑config/routes.rb:
Rails.application.routes.draw do root to: 'invoices#index' resources :invoices, only: [:index, :show] end
启动 rails server 并导航到 localhost:3000 以查看发票列表:

app/views/invoices/show.html.erb
<div class="invoice">
<h1>Envato Invoice</h1>
<h3>To: <%= @invoice.client %></h3>
<h3>Date: <%= @invoice.date.strftime("%B %d, %Y") %></h3>
<table>
<thead>
<tr>
<th>Description</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<% @invoice.line_items.each do |line_item| %>
<tr>
<td><%= line_item.description %></td>
<td><%= number_to_currency(line_item.price) %></td>
</tr>
<% end %>
<tr class="total">
<td style="text-align: right">Total: </td>
<td><%= number_to_currency(@invoice.total) %></span></td>
</tr>
</tbody>
</table>
<% if @invoice.notes %>
<div class="notes">
<p><strong>Notes:</strong> <%= @invoice.notes %></p>
</div>
<% end %>
</div>
此发票详细信息页面的 CSS 已移至 app/assets/stylesheets/application.scss
.invoice {
width: 700px;
max-width: 700px;
border: 1px solid grey;
margin: 50px;
padding: 50px;
h1 {
text-align: center;
margin-bottom: 100px;
}
.notes {
margin-top: 100px;
}
table {
width: 90%;
text-align: left;
}
th {
padding-bottom: 15px;
}
.total td {
font-size: 20px;
font-weight: bold;
padding-top: 25px;
}
}
然后,当您点击主列表页面中的发票时,您将看到详细信息:

此时,我们已准备好向 Rails 应用程序添加查看或下载 PDF 格式的发票的功能。
为了将 Rails 应用中的发票呈现为 PDF,我们需要将三个 gem 添加到 Gemfile 中:PDFKit、render_anywhere 和 wkhtmltopdf-binary。默认情况下,rails 只允许您从控制器渲染模板,但通过使用 render_anywhere,我们可以从模型或后台作业渲染模板。
gem 'pdfkit' gem 'render_anywhere' gem 'wkhtmltopdf-binary'
为了不让太多逻辑污染我们的控制器,我将在 app/models 文件夹中创建一个新的 InvoicePdf 类,以将逻辑包装到生成 PDF。
require "render_anywhere"
class InvoicePdf
include RenderAnywhere
def initialize(invoice)
@invoice = invoice
end
def to_pdf
kit = PDFKit.new(as_html, page_size: 'A4')
kit.to_file("#{Rails.root}/public/invoice.pdf")
end
def filename
"Invoice #{invoice.id}.pdf"
end
private
attr_reader :invoice
def as_html
render template: "invoices/pdf", layout: "invoice_pdf", locals: { invoice: invoice }
end
end
此类只是将发票作为类构造函数的参数进行渲染。私有方法 as_html 是 读取视图模板 invoices/pdf 和 layout_pdf 我们用来生成需要渲染为 PDF 的 HTML。最后,方法 to_pdf 使用 PDFKit 将 PDF 文件保存在 Rails 公共文件夹中。
您可能希望在实际应用程序中生成动态名称,以便 PDF 文件不会被意外覆盖。您可能也希望将文件存储在 AWS S3 或私有文件夹上,但这超出了本教程的范围。
<div class="invoice">
<h1>Envato Invoice</h1>
<h3>To: <%= invoice.client %></h3>
<h3>Date: <%= invoice.date.strftime("%B %d, %Y") %></h3>
<table>
<thead>
<tr>
<th>Description</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<% invoice.line_items.each do |line_item| %>
<tr>
<td><%= line_item.description %></td>
<td><%= number_to_currency(line_item.price) %></td>
</tr>
<% end %>
<tr class="total">
<td style="text-align: right">Total: </td>
<td><%= number_to_currency(invoice.total) %></span></td>
</tr>
</tbody>
</table>
<% if invoice.notes %>
<div class="notes">
<p><strong>Notes:</strong> <%= invoice.notes %></p>
</div>
<% end %>
</div>
<!DOCTYPE html>
<html>
<head>
<title>Envato Invoices</title>
<style>
<%= Rails.application.assets.find_asset('application.scss').to_s %>
</style>
</head>
<body>
<%= yield %>
</body>
</html>
在此布局文件中需要注意的一件事是我们正在布局中渲染样式。如果我们以这种方式呈现样式,WkHtmlToPdf 确实会工作得更好。
此时我们需要一个调用类 InvoicePdf 的路由和控制器来将 PDF 文件发送到浏览器,因此编辑 config/routes.rb 添加嵌套资源:
Rails.application.routes.draw do
root to: "invoices#index"
resources :invoices, only: [:index, :show] do
resource :download, only: [:show]
end
end
如果我们运行 rake paths,我们会看到应用程序中可用的路由列表:
Prefix Verb URI Pattern Controller#Action
root GET / invoices#index
invoice_download GET /invoices/:invoice_id/download(.:format) downloads#show
invoices GET /invoices(.:format) invoices#index
invoice GET /invoices/:id(.:format) invoices#show
添加 app/controllers/downloads_controller.rb:
class DownloadsController < ApplicationController
def show
respond_to do |format|
format.pdf { send_invoice_pdf }
end
end
private
def invoice_pdf
invoice = Invoice.find(params[:invoice_id])
InvoicePdf.new(invoice)
end
def send_invoice_pdf
send_file invoice_pdf.to_pdf,
filename: invoice_pdf.filename,
type: "application/pdf",
disposition: "inline"
end
end
如您所见,当请求请求 PDF 文件时,方法 send_invoice_pdf 正在处理该请求。方法 invoice_pdf 只是通过 id 从数据库中查找发票,并创建 InvoicePdf 的实例。那么 send_invoice_pdf 只是调用方法 to_pdf ,将生成的 PDF 文件发送到浏览器。
需要注意的一点是,我们将参数 disposition: "inline" 传递给 send_file。该参数是将文件发送到浏览器,并显示出来。如果您想强制下载文件,则需要传递 disposition: "attachment" 。
向发票显示模板 app/views/invoices/show.html.erb 添加下载按钮:
<%= link_to "Download PDF",
invoice_download_path(@invoice, format: "pdf"),
target: "_blank",
class: "download" %>
运行应用程序,导航到发票详细信息,单击下载,然后将打开一个新选项卡,显示 PDF 发票。

当您处理 PDF 标记时,每次想要测试更改时都必须生成 PDF,有时可能会很慢。因此,能够以纯 HTML 形式查看将转换为 PDF 的 HTML 非常有用。我们只需要编辑/app/controllers/downloads_controller.rb即可。
class DownloadsController < ApplicationController
def show
respond_to do |format|
format.pdf { send_invoice_pdf }
if Rails.env.development?
format.html { render_sample_html }
end
end
end
private
def invoice
Invoice.find(params[:invoice_id])
end
def invoice_pdf
InvoicePdf.new(invoice)
end
def send_invoice_pdf
send_file invoice_pdf.to_pdf,
filename: invoice_pdf.filename,
type: "application/pdf",
disposition: "inline"
end
def render_sample_html
render template: "invoices/pdf", layout: "invoice_pdf", locals: { invoice: invoice }
end
end
现在 show 方法也在开发模式下响应 HTML 请求。 PDF 发票的路径类似于 http://localhost:3000/invoices/1/download.pdf。如果您将其更改为 http://localhost:3000/invoices/1/download.html,您将看到 HTML 格式的发票,其中使用了用于生成 PDF 的标记。
根据上面的代码,假设您熟悉 Ruby 语言和 Rails 框架,使用 Ruby on Rails 生成 PDF 文件非常简单。也许整个过程最好的一点是您不必学习任何新的标记语言或有关 PDF 生成的细节。
我希望本教程是有用的。请在评论中留下任何问题、评论和反馈,我很乐意跟进。
以上就是Rails实现HTML转PDF的方法的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号