有很多方法可以在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>
kit.to_file("hello.pdf")
您应该有一个名为hello.pdf的新文件,其文本位于顶部。
require "pdfkit"
PDFKit.new('https://www.google.com', :page_size => 'A3').to_file('google.pdf')
如您所见,我指定的是
page_size
默认情况下,使用A4。 您可以
在此处
查看选项的完整列表。
使用CSS样式化PDF
之前我提到过,我们将使用HTML和CSS生成PDF文件。 在此示例中,我添加了一些CSS来为示例发票HTML样式设置,如您所见:
require "pdfkit"
kit = PDFKit.new(<<-HTML)
<style>
color: grey;
text-align: center;
color: black;
margin-bottom: 100px;
.notes {
margin-top: 100px;
table {
width: 100%;
text-align: left;
color: black;
padding-bottom: 15px;
</style>
<h1>Envato Invoice</h1>
<table>
<thead>
<th>Description</th>
<th>Price</th>
</thead>
<tbody>
<td>Monthly Subscription to Tuts+</td>
<td>$15</td>
</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>
kit.to_file("envato_invoice.pdf")
如果运行此脚本,将生成文件
envato_invoice.pdf
。 这张照片显示了发票示例的结果:
如您所见,如果您已经熟悉HTML和CSS,则PDFKit非常易于使用。 您可以根据需要继续自定义或样式化该文档。
从Rails应用程序使用PDFKit
现在让我们看一下如何在Rails应用程序的上下文中使用PDFKit,以便我们可以使用模型中的数据动态生成PDF文件。 在本节中,我们将构建一个简单的Rails应用程序,以动态生成先前的“ Envato发票”。 首先创建一个新的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生成器,运行
rails generate controller Invoices index show
清单可以
rails generate controller Invoices index show
创建控制器和视图。
app / controllers / invoices_controller.rb
class InvoicesController < ApplicationController
def index
@invoices = Invoice.all
def show
@invoice = Invoice.find(params[:id])
app / views / invoices / index.html.erb
<h1>Invoices</h1>
<% @invoices.each do |invoice| %>
<%= link_to "#{invoice.id} - #{invoice.client} - #{invoice.date.strftime("%B %d, %Y")} ", invoice_path(invoice) %>
<% end %>
我们需要修改Rails路由以默认情况下重定向到InvoicesController
,因此请编辑config/routes.rb
:
Rails.application.routes.draw do
root to: 'invoices#index'
resources :invoices, only: [:index, :show]
启动rails server
,然后导航到localhost:3000以查看发票列表:
<tr class="total">
<td style="text-align: right">Total: </td>
<td><%= number_to_currency(@invoice.total) %></span></td>
</tbody>
</table>
<% if @invoice.notes %>
<div class="notes">
<p><strong>Notes:</strong> <%= @invoice.notes %></p>
<% end %>
此发票详细信息页面CSS已移至app / assets / stylesheets / application.scss
.invoice {
width: 700px;
max-width: 700px;
border: 1px solid grey;
margin: 50px;
padding: 50px;
text-align: center;
margin-bottom: 100px;
.notes {
margin-top: 100px;
table {
width: 90%;
text-align: left;
padding-bottom: 15px;
.total td {
font-size: 20px;
font-weight: bold;
padding-top: 25px;
然后,在主列表页面上单击发票时,您将看到详细信息:
至此,我们准备将功能添加到Rails应用程序中,以查看或下载PDF发票。
用于处理PDF渲染的InvoicePdf类
为了将发票从Rails应用程序呈现为PDF,我们需要在Gemfile中添加三个gem: 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
def to_pdf
kit = PDFKit.new(as_html, page_size: 'A4')
kit.to_file("#{Rails.root}/public/invoice.pdf")
def filename
"Invoice #{invoice.id}.pdf"
private
attr_reader :invoice
def as_html
render template: "invoices/pdf", layout: "invoice_pdf", locals: { invoice: invoice }
此类仅将发票呈现为类构造函数上的参数。 私有方法as_html
是 阅读我们用于生成需要呈现为PDFHTML的视图模板invoices/pdf
和layout_pdf
。 最后,方法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>
<th>Description</th>
<th>Price</th>
</thead>
<tbody>
<% invoice.line_items.each do |line_item| %>
<td><%= line_item.description %></td>
<td><%= number_to_currency(line_item.price) %></td>
<% end %>
<tr class="total">
<td style="text-align: right">Total: </td>
<td><%= number_to_currency(invoice.total) %></span></td>
</tbody>
</table>
<% if invoice.notes %>
<div class="notes">
<p><strong>Notes:</strong> <%= invoice.notes %></p>
<% end %>
/app/views/layouts/invoice_pdf.erb
<!DOCTYPE html>
<title>Envato Invoices</title>
<style>
<%= Rails.application.assets.find_asset('application.scss').to_s %>
</style>
</head>
<%= yield %>
</body>
</html>
在此布局文件中要注意的一件事是,我们正在布局中渲染样式。 如果我们以这种方式渲染样式,WkHtmlToPdf的效果会更好。
下载控制器以呈现PDF发票
此时,我们需要一个路由和控制器,调用类InvoicePdf
将PDF文件发送到浏览器,因此请编辑config/routes.rb
以添加嵌套资源:
Rails.application.routes.draw do
root to: "invoices#index"
resources :invoices, only: [:index, :show] do
resource :download, only: [:show]
如果运行rake routes
,我们将在应用程序中看到可用的路由列表:
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 }
private
def invoice_pdf
invoice = Invoice.find(params[:invoice_id])
InvoicePdf.new(invoice)
def send_invoice_pdf
send_file invoice_pdf.to_pdf,
filename: invoice_pdf.filename,
type: "application/pdf",
disposition: "inline"
如您所见,当请求要求提供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呈现为HTML
当您处理PDF标记时,有时每次要测试更改都必须生成PDF有时会很慢。 因此,能够查看将要转换为纯HTMLHTML确实有用。 我们只需要编辑/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 }
private
def invoice
Invoice.find(params[:invoice_id])
def invoice_pdf
InvoicePdf.new(invoice)
def send_invoice_pdf
send_file invoice_pdf.to_pdf,
filename: invoice_pdf.filename,
type: "application/pdf",
disposition: "inline"
def render_sample_html
render template: "invoices/pdf", layout: "invoice_pdf", locals: { invoice: invoice }
现在, show
方法还在开发模式下响应HTML请求。 PDF发票的路由应类似于http:// localhost:3000 / invoices / 1 / download.pdf 。 如果将其更改为http:// localhost:3000 / invoices / 1 / download.html ,则将使用用于生成PDF的标记在HTML中看到发票。
给定上面的代码,假设您熟悉Ruby语言和Rails框架,那么使用Ruby on Rails生成PDF文件非常简单。 也许整个过程最好的方面是,您不必学习任何新的标记语言或有关PDF生成的细节。
希望本教程对您有所帮助。 请在评论中留下任何问题,评论和反馈,我很乐意跟进。
翻译自: https://code.tutsplus.com/tutorials/generating-pdfs-from-html-with-rails--cms-22918
有很多方法可以在Ruby和Rails中生成PDF。 您可能已经熟悉HTML和CSS,因此我们将使用PDFKit从标准Rails视图和样式代码使用HTML生成PDF文件。 PDFKit简介 在内部,PDFKit使用wkhtmltopdf(WebKit HTML到PDF),该引擎将采用HTML和CSS,使用WebKit对其进行呈现,然后将其输出为高质量的PDF。 首先,在计算机上安装wkh...