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

Rails应用中PDF上传成功却无法下载的问题求助

问题

在Rails应用中遇到了一个奇怪的问题:通过API上传PDF文件,文件通过has_one_attached :file关联到Document对象,对应的create方法代码如下:

def create
    if can? :create, Document
      @document = Document.new(document_params.except(:upload_files))

      if document_params[:upload_files].present?
        uploaded_file = document_params[:upload_files].first
        @document.file_name = uploaded_file.original_filename
        @document.file_size = uploaded_file.size.to_s
        @document.file_type = uploaded_file.content_type
        @document.file.attach(io: uploaded_file.tempfile, filename: uploaded_file.original_filename, content_type: "application/pdf", identify: false).save
      end

      if @document.save
        redirect_to document_path(@organization, id: @document.id), notice: "Document successfully saved."
      else
        redirect_to root_path, alert: "Document could not be saved."
      end
    else
      raise CanCan::AccessDenied
    end
  end

在控制台执行doc.file.attached?返回true,数据库中也能查到文件关联记录。但调用Download API生成下载链接后,通过AJAX获取链接并触发下载时,浏览器提示‘the file wasn't available on site’,下载的文件为空或不存在。相关Download方法和AJAX代码如下:

def download
    respond_to do |format|
      format.json do
        if @document.file.attached?
          file_url = rails_blob_url(@document.file, disposition: "attachment", content_type: @document.file_type)
          render json: { document: { file: file_url } }
        else
          render json: { error: "File not found" }, status: :not_found
        end
      end
      format.html { proxy_attachment_file_render(@document.file) }
    end
  end
$.ajax({
        url: 'path/to/download/api'
        dataType: 'json',
        method: 'GET',
        success: function(response) {
        console.log(response)
        if (response.document && response.document.file) {
            const fileUrl = response.document.file;
            const link = document.createElement('a');
            link.href = fileUrl;
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
        } else {
          alert('File not available for download.');
        }
      },
      error: function() { alert('Error fetching the file.');}
});

明明文件已成功上传并关联到对象,却无法正常下载,请问哪里操作有误?

排查与解决思路

1. 验证Blob URL的有效性

直接把AJAX返回的fileUrl粘贴到浏览器地址栏访问,看是否能正常下载:

  • 若直接访问也失败,说明问题出在Active Storage服务端:
    • 本地存储场景:检查storage目录下是否存在对应文件,且服务器进程有读写权限。
    • 云存储场景(如S3):确认存储桶权限允许访问,同时核对Rails的云存储配置是否正确。

2. 移除identify: false参数

上传时设置identify: false会跳过Rails对文件类型的自动检测,可能导致Blob元数据不完整。尝试修改上传代码:

@document.file.attach(io: uploaded_file.tempfile, filename: uploaded_file.original_filename, content_type: uploaded_file.content_type)

3. 修复AJAX的CSRF或跨域问题

  • Rails默认启用CSRF保护,AJAX请求需携带CSRF令牌,补充请求头:
$.ajax({
  url: 'path/to/download/api',
  dataType: 'json',
  method: 'GET',
  headers: {
    'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
  },
  // 其余代码不变
});
  • 若存在跨域场景,需配置CORS规则允许Blob资源的跨域访问。

4. 检查proxy_attachment_file_render方法

该自定义方法可能存在逻辑错误,可暂时替换为Rails内置的文件返回方式测试:

format.html do
  send_data @document.file.download, filename: @document.file.filename, type: @document.file.content_type, disposition: 'attachment'
end

5. 确认参数白名单配置

确保document_params中包含:upload_files,否则文件可能未实际上传:

def document_params
  params.require(:document).permit(:name, :description, upload_files: [])
end

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 17:53:12