You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rails中如何将Template模型参数传递给Prawn生成的PDF视图

实现方案

1. 改造Prawn PDF类支持参数传入

首先修改ReportPdf的初始化方法,支持接收动态参数,为了兼容多类型PDF的通用需求,直接用哈希传参即可:

class ReportPdf < Prawn::Document
  # 新增参数接收,args为哈希,可传入任意你需要的动态数据
  def initialize(args = {})
    # 调用父类构造方法,也可以在这里传pdf全局配置,比如页面大小、边距等
    super()
    # 把传入的参数存为实例变量,所有实例方法都可以调用
    @template = args[:template]
    @templates = args[:templates]
    header
    text_content
  end

  def header
    image "#{Rails.root}/app/assets/images/logo.jpg", width: 230, height: 75
  end

  def text_content
    y_position = cursor - 50

    bounding_box([0, y_position], :width => 270, :height => 300) do
      # 替换成动态内容即可
      text "表单信息", size: 15, style: :bold
      text "This form is for #{@template.name} who lives at #{@template.address} and has an id of #{@template.NationalId}"
      text "Lorem ipsum dolor sit amet, consectetur adipiscing elit. ."
    end

    bounding_box([300, y_position], :width => 270, :height => 300) do
      text "Duis vel", size: 15, style: :bold
      text "Duis vel tortor elementum, ultrices tortor vel, accumsan dui. Nullam in dolor rutrum, gravida turpis eu, vestibulum lectus. Pellentesque aliquet dignissim justo ut fringilla. Interdum et malesuada fames ac ante ipsum primis in faucibus. Ut venenatis massa non eros venenatis aliquet. Suspendisse potenti. Mauris sed tincidunt mauris, et vulputate risus. Aliquam eget nibh at erat dignissim aliquam non et risus. Fusce mattis neque id diam pulvinar, fermentum luctus enim porttitor. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos."
    end
  end
end

2. 控制器层传递数据

根据你生成PDF的场景,在对应控制器动作里把模型数据传入PDF类即可:

单条Template详情PDF(对应show页面)

给show动作新增pdf响应逻辑:

def show
  respond_to do |format|
    format.html
    format.pdf do
      # 把查询到的@template传入PDF类
      pdf = ReportPdf.new(template: @template)
      send_data pdf.render, filename: "template_#{@template.id}.pdf", type: 'application/pdf', disposition: "inline"
    end
  end
end

多条Template列表PDF(对应index页面)

如果要生成所有模板的汇总PDF,直接传入集合即可:

def index
  @templates = Template.all

  respond_to do |format|
    format.html
    format.pdf do
      pdf = ReportPdf.new(templates: @templates)
      send_data pdf.render, filename: 'templates_report.pdf', type: 'application/pdf', disposition: "inline"
    end
  end
end

3. 多类型PDF通用适配方案

要支持报告、证书等不同类型的PDF,你可以抽一个公共PDF基类,把通用逻辑(比如页眉、页脚、字体配置)放在基类里,不同类型的PDF继承基类实现各自的内容逻辑即可:

# app/pdfs/base_pdf.rb
class BasePdf < Prawn::Document
  def initialize(args = {})
    # 统一配置页面大小、边距、字体等
    super(page_size: 'A4', margin: 30)
    set_font
    header
    content
    footer
  end

  def set_font
    # 统一配置字体,支持中文的话可以在这里加载自定义字体
  end

  def header
    # 通用页眉逻辑,比如Logo、站点名称
  end

  def footer
    # 通用页脚逻辑,比如页码、版权信息
  end

  def content
    # 子类各自实现
    raise NotImplementedError, "子类需要实现content方法"
  end
end

# 报告类PDF
class ReportPdf < BasePdf
  def initialize(args = {})
    @templates = args[:templates]
    super
  end

  def content
    # 报告专属内容逻辑
  end
end

# 证书类PDF
class CertificatePdf < BasePdf
  def initialize(args = {})
    @user = args[:user]
    @course = args[:course]
    super
  end

  def content
    # 证书专属内容逻辑
  end
end

额外修正

你的表单代码里重复写了两次address字段,把第二个address字段替换为name字段,否则提交表单时无法获取name参数:

<div class="field">
  <%= form.label :name %>
  <%= form.text_field :name %>
</div>

<div class="field">
  <%= form.label :address %>
  <%= form.text_field :address %>
</div>

<div class="field">
  <%= form.label :NationalId %>
  <%= form.text_field :NationalId %>
</div>

内容的提问来源于stack exchange,提问作者dragoon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 11:54:03