0

0

Rails实现HTML转PDF的方法

王林

王林

发布时间:2023-08-27 12:49:15

|

1067人浏览过

|

来源于php中文网

原创

在 ruby 和 rails 中生成 pdf 的方法有很多种。您可能已经熟悉 html 和 css,因此我们将使用 pdfkit 通过标准 rails 视图和样式代码中的 html 生成 pdf 文件。

PDFKit 简介

在内部,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><p><span>立即学习</span>“<a href="https://pan.quark.cn/s/cb6835dc7db1" style="text-decoration: underline !important; color: blue; font-weight: bolder;" rel="nofollow" target="_blank">前端免费学习笔记(深入)</a>”;</p>
HTML

kit.to_file("hello.pdf")

您应该有一个名为 hello.pdf 的新文件,其文本位于顶部。

Rails实现HTML转PDF的方法

PDFKit 还允许您从 URL 生成 PDF。如果您想从 Google 主页生成 PDF,您可以运行:

require "pdfkit"

PDFKit.new('https://www.google.com', :page_size => 'A3').to_file('google.pdf')

如您所见,我指定了 page_size — 默认情况下使用 A4。您可以在此处查看完整的选项列表。

Rails实现HTML转PDF的方法

使用 CSS 设置 PDF 样式

之前我提到过我们将使用 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。这张照片显示了样本发票的结果:

Rails实现HTML转PDF的方法

如您所见,如果您已经熟悉 HTML 和 CSS,则 PDFKit 非常易于使用。您可以根据需要继续自定义此文档或设计其样式。

在 Rails 应用程序中使用 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 以查看发票列表:

Rails实现HTML转PDF的方法

SV-Cart网店系统
SV-Cart网店系统

SV-Cart是开源的电子商务平台。多语言,国际化SV-CART网店系统是一套可以支持各个国家的语言显示的国际电子商务系统,现已支持中文简体、英文、日文、德文和法文,土耳其文,可实现这五种语言在同一平台上的相互转换。免费、开源SV-CART网店系统是一项新的专业开放源代码的WEB2.0网上商城系统,是一套集网上购物和网站内容管理于一体的电子商务解决方案。易操作、多功能SV-CART系统注重操作上的

下载

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实现HTML转PDF的方法

此时,我们已准备好向 Rails 应用程序添加查看或下载 PDF 格式的发票的功能。

处理 PDF 渲染的 InvoicePdf 类

为了将 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/pdflayout_pdf 我们用来生成需要渲染为 PDF 的 HTML。最后,方法 to_pdf  使用 PDFKit 将 PDF 文件保存在 Rails 公共文件夹中。

您可能希望在实际应用程序中生成动态名称,以便 PDF 文件不会被意外覆盖。您可能也希望将文件存储在 AWS S3 或私有文件夹上,但这超出了本教程的范围。

/app/views/invoices/pdf.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>

/app/views/layouts/invoice_pdf.erb

<!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 确实会工作得更好。

用于呈现 PDF 发票的 DownloadsController

此时我们需要一个调用类 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 发票。

Rails实现HTML转PDF的方法

在开发中将 PDF 渲染为 HTML

当您处理 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 生成的细节。

我希望本教程是有用的。请在评论中留下任何问题、评论和反馈,我很乐意跟进。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

16

2026.03.11

Go高并发任务调度与Goroutine池化实践
Go高并发任务调度与Goroutine池化实践

本专题围绕 Go 语言在高并发任务处理场景中的实践展开,系统讲解 Goroutine 调度模型、Channel 通信机制以及并发控制策略。内容包括任务队列设计、Goroutine 池化管理、资源限制控制以及并发任务的性能优化方法。通过实际案例演示,帮助开发者构建稳定高效的 Go 并发任务处理系统,提高系统在高负载环境下的处理能力与稳定性。

23

2026.03.10

Kotlin Android模块化架构与组件化开发实践
Kotlin Android模块化架构与组件化开发实践

本专题围绕 Kotlin 在 Android 应用开发中的架构实践展开,重点讲解模块化设计与组件化开发的实现思路。内容包括项目模块拆分策略、公共组件封装、依赖管理优化、路由通信机制以及大型项目的工程化管理方法。通过真实项目案例分析,帮助开发者构建结构清晰、易扩展且维护成本低的 Android 应用架构体系,提升团队协作效率与项目迭代速度。

75

2026.03.09

JavaScript浏览器渲染机制与前端性能优化实践
JavaScript浏览器渲染机制与前端性能优化实践

本专题围绕 JavaScript 在浏览器中的执行与渲染机制展开,系统讲解 DOM 构建、CSSOM 解析、重排与重绘原理,以及关键渲染路径优化方法。内容涵盖事件循环机制、异步任务调度、资源加载优化、代码拆分与懒加载等性能优化策略。通过真实前端项目案例,帮助开发者理解浏览器底层工作原理,并掌握提升网页加载速度与交互体验的实用技巧。

95

2026.03.06

Rust内存安全机制与所有权模型深度实践
Rust内存安全机制与所有权模型深度实践

本专题围绕 Rust 语言核心特性展开,深入讲解所有权机制、借用规则、生命周期管理以及智能指针等关键概念。通过系统级开发案例,分析内存安全保障原理与零成本抽象优势,并结合并发场景讲解 Send 与 Sync 特性实现机制。帮助开发者真正理解 Rust 的设计哲学,掌握在高性能与安全性并重场景中的工程实践能力。

218

2026.03.05

PHP高性能API设计与Laravel服务架构实践
PHP高性能API设计与Laravel服务架构实践

本专题围绕 PHP 在现代 Web 后端开发中的高性能实践展开,重点讲解基于 Laravel 框架构建可扩展 API 服务的核心方法。内容涵盖路由与中间件机制、服务容器与依赖注入、接口版本管理、缓存策略设计以及队列异步处理方案。同时结合高并发场景,深入分析性能瓶颈定位与优化思路,帮助开发者构建稳定、高效、易维护的 PHP 后端服务体系。

420

2026.03.04

AI安装教程大全
AI安装教程大全

2026最全AI工具安装教程专题:包含各版本AI绘图、AI视频、智能办公软件的本地化部署手册。全篇零基础友好,附带最新模型下载地址、一键安装脚本及常见报错修复方案。每日更新,收藏这一篇就够了,让AI安装不再报错!

168

2026.03.04

Swift iOS架构设计与MVVM模式实战
Swift iOS架构设计与MVVM模式实战

本专题聚焦 Swift 在 iOS 应用架构设计中的实践,系统讲解 MVVM 模式的核心思想、数据绑定机制、模块拆分策略以及组件化开发方法。内容涵盖网络层封装、状态管理、依赖注入与性能优化技巧。通过完整项目案例,帮助开发者构建结构清晰、可维护性强的 iOS 应用架构体系。

222

2026.03.03

C++高性能网络编程与Reactor模型实践
C++高性能网络编程与Reactor模型实践

本专题围绕 C++ 在高性能网络服务开发中的应用展开,深入讲解 Socket 编程、多路复用机制、Reactor 模型设计原理以及线程池协作策略。内容涵盖 epoll 实现机制、内存管理优化、连接管理策略与高并发场景下的性能调优方法。通过构建高并发网络服务器实战案例,帮助开发者掌握 C++ 在底层系统与网络通信领域的核心技术。

33

2026.03.03

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
CSS3 教程
CSS3 教程

共18课时 | 7万人学习

PostgreSQL 教程
PostgreSQL 教程

共48课时 | 10.5万人学习

TypeScript 教程
TypeScript 教程

共19课时 | 3.4万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号