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

将WickedPdf生成的PDF保存到Active Storage后损坏的排查与修复

问题描述

我希望将生成的PDF保存为Active Storage附件。

生成PDF并存储的代码:

pdf = WickedPdf.new.pdf_from_string(
      render_to_string(pdf: 'SurveyReportForm', template: '/screenings/test', layout: 'pdf',  formats: :pdf)
     )

@screening.report.attach(
  io: StringIO.new(pdf),
  filename: "#{@screening.id}-report",
  content_type: 'application/pdf'
)

代码运行无报错,但点击下载链接查看PDF时:

<%= link_to "Download Report", rails_blob_path(@screening.report, disposition: "attachment") %>

打开的PDF显示类似二进制/源码内容,开头为:

%PDF-1.4 1 0 obj << /Title (þÿ) /Creator (þÿwkhtmltopdf 0.12.6) /Producer (þÿQt 4.8.7...

请问问题出在哪里?如何排查是PDF生成环节还是存储环节的问题,以及该如何修复?


问题分析与解决

核心问题

你遇到的是编码不匹配问题:WickedPdf生成的PDF是二进制数据,但render_to_string默认返回UTF-8编码的字符串,直接转成StringIO会导致二进制数据被错误解析,存储后打开就会显示乱码的源码内容。

排查步骤

  • 验证PDF生成环节:
    在生成代码后,先把PDF写入本地文件测试:
    File.open('/tmp/test.pdf', 'wb') { |f| f.write(pdf) }
    
    打开本地的test.pdf,如果能正常显示,说明生成环节没问题;如果还是乱码,那是WickedPdf的配置问题(比如模板编码、wkhtmltopdf参数)。
  • 验证存储环节:
    如果本地文件正常,那问题出在Active Storage的存储过程。检查StringIO的初始化是否正确:二进制数据需要用二进制模式的IO对象,而默认StringIO.new(pdf)是文本模式,会破坏二进制数据。

修复方案

方案1:修正StringIO模式

直接指定StringIO为二进制模式初始化:

@screening.report.attach(
  io: StringIO.new(pdf, 'rb'), # 启用二进制模式
  filename: "#{@screening.id}-report.pdf", # 建议添加.pdf后缀,确保系统识别文件类型
  content_type: 'application/pdf'
)

方案2:使用Tempfile(更稳定)

用临时文件暂存二进制数据,避免字符串编码干扰:

temp_file = Tempfile.new(["#{@screening.id}-report", '.pdf'], binmode: true)
begin
  temp_file.write(pdf)
  temp_file.rewind # 将文件指针移到开头,确保Active Storage能读取完整内容
  @screening.report.attach(
    io: temp_file,
    filename: "#{@screening.id}-report.pdf",
    content_type: 'application/pdf'
  )
ensure
  temp_file.close
  temp_file.unlink # 清理临时文件
end

额外优化建议

  • 给文件名加上.pdf后缀,避免部分系统无法识别文件类型;
  • 尝试去掉render_to_string中的formats: :pdf参数,因为WickedPdf的pdf_from_string已经专门处理PDF渲染,该参数可能导致额外的编码转换。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 13:50:40