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

Rails 7.0中send_data无法在新标签页打开PDF的问题

问题原因及解决方法

核心问题

Rails 7默认启用了Turbo,你用button_to生成的是POST表单,Turbo会自动拦截这个请求并以TURBO_STREAM格式处理,但你的openPDF动作返回的是PDF二进制数据,Turbo无法解析这种非HTML/Turbo Stream的响应,所以没法在新标签页正常打开。而把代码移到index动作时,你是直接通过GET请求访问(没有Turbo拦截),所以能正常显示PDF。

解决方法

有两种简单的修复方式:

方式1:禁用Turbo并指定新标签页打开

给button_to添加data: { turbo: false },让浏览器用原生方式处理这个POST请求,同时加上target: "_blank"指定在新标签页打开:

<%= button_to 'Open', welcome_openPDF_path(pdf_file: file), method: :post, data: { turbo: false }, target: "_blank" %>

方式2:改用GET请求(更适合资源获取场景)

如果你的PDF文件路径不需要保密,建议改用GET请求,直接用link_to更符合REST规范,同时路由也要改成GET:

  • 修改routes.rb:
get 'welcome/openPDF'
  • 修改视图代码:
<%= link_to 'Open', welcome_openPDF_path(pdf_file: file), target: "_blank" %>

重要安全提醒

你当前的open(params[:pdf_file])存在严重的目录遍历攻击风险,攻击者可以通过构造pdf_file参数访问服务器上任意文件(比如../../../../etc/passwd)。必须限制文件的访问范围,比如只允许访问public/pdfs目录下的文件:

def openPDF
  # 限定文件在指定目录内
  allowed_dir = Rails.root.join('public', 'pdfs')
  safe_path = allowed_dir.join(params[:pdf_file]).cleanpath

  # 验证路径是否在允许的目录范围内
  unless safe_path.absolute? && safe_path.starts_with?(allowed_dir)
    raise ActionController::RoutingError, 'Not Found'
  end

  data = open(safe_path, 'rb').read
  send_data(data, type: 'application/pdf', filename: params[:pdf_file], disposition: 'inline')
end

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 09:52:11