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

如何使用Prawn gem在Rails应用中实现可选择类型的多PDF生成功能

实现方案

第一步:统一PDF类的入参规范

你现有PDF类中直接使用了@template变量,但初始化时没有传入该参数,首先需要修正所有Pdf类的构造方法,统一接收template参数:

class ReportPdf < Prawn::Document
  # 新增template参数接收业务数据
  def initialize(template)
    super()
    @template = template
    header
    text_content
  end

  # 原有header、text_content等方法保持不变
  def header
    image "#{Rails.root}/app/assets/images/logo.jpg", width: 230, height: 75
  end

  def text_content
    bounding_box([0, y_position], :width => 270, :height => 300) do
      text "This is a sample report by #{@template.name} who lives at #{@template.address} etc etc"
    end
  end
end

所有出生证明、契约、发票等PDF类都按这个规则修改initialize方法即可。

第二步:控制器新增合法PDF类型映射

在控制器中定义常量保存合法PDF类型的映射关系,禁止直接将用户传入的参数转为类名,避免恶意调用风险:

class TemplatesController < ApplicationController
  # 合法PDF类型映射,key为表单提交的pdf_type值,value对应PDF类和导出文件名
  PDF_TYPE_MAPPING = {
    'Report' => { klass: 'ReportPdf', filename: '报告.pdf' },
    'Birth_certificate' => { klass: 'BirthCertificatePdf', filename: '出生证明.pdf' },
    'Deed' => { klass: 'DeedPdf', filename: '契约.pdf' },
    'Title' => { klass: 'TitlePdf', filename: '产权证明.pdf' }
  }.freeze

  before_action :set_template, only: %i[ show edit update destroy ]

  def show
    respond_to do |format|
      format.html
      format.pdf do
        # 校验PDF类型合法性
        pdf_config = PDF_TYPE_MAPPING[params[:pdf_type]]
        unless pdf_config
          flash[:error] = "不支持的PDF类型"
          redirect_to template_path(@template) and return
        end

        # 动态实例化对应PDF类,传入模板数据
        pdf_klass = pdf_config[:klass].constantize
        pdf = pdf_klass.new(@template)

        send_data pdf.render, 
                  filename: pdf_config[:filename], 
                  type: 'application/pdf', 
                  disposition: "inline"
      end
    end
  end

  # 其余原有代码保持不变
  def template_params
    params.require(:template).permit(:name, :address, :idnumber)
  end
end

第三步:调整表单提交地址

你现有表单提交到的是templates_path(对应index动作),如果需要加载单条template的数据生成PDF,需要把表单提交地址改为对应template的show路径:

<!-- 表单放在template详情页时,提交地址指向当前template的pdf响应路径 -->
<%= form_with url: template_path(@template, format: "pdf"), local: true, method: :get do |form| %>
  <%= form.label :pdf_type %>
  <%= form.select :pdf_type,
    options_for_select([
      ['报告','Report'],
      ['出生证明','Birth_certificate'],
      ['契约','Deed'],
      ['产权证明','Title']]),
    {}, {class: "form-control" } %> 

  <%= form.button "下载", class: "btn btn-primary" %>
<% end %>

如果需要批量生成PDF,调整index动作的逻辑和参数传递规则即可,核心的动态调用PDF类的逻辑完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 01:27:03