如何使用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
相关产品推荐
相关产品推荐

