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

Ruby on Rails:多Word文件打包Zip单次send_data及空字节错误排查

Solution: Send Multiple Word Files as a Single Zip Attachment

Why You're Getting the Multiple Renders Error

You can only send one HTTP response per request. Calling send_data inside a loop tries to send multiple attachments, which Rails blocks with the Multiple Renders error. The fix is to bundle all Word files into a single zip archive and send that once.


Option 1: Forward the Original Zip from the API

If the API already returns a zip containing all your Word files, you can send the raw response directly without processing:

def generate_multi_letter(template, letterName, params)
  @Document_URL = "#{ENV["API_HOST"]}/api/StateDocument/GenerateDocX/#{template}"
  response = HTTParty.post(@Document_URL,
                           body: params.to_json,
                           headers: { "Content-Type" => "application/json" })

  send_data response.body,
    filename: "#{letterName}.zip",
    type: "application/zip",
    disposition: "attachment"
end

Option 2: Create a Custom Zip (for File Renaming/Processing)

If you need to modify the files (e.g., rename entries) before sending, use an in-memory zip (via StringIO) to avoid writing to disk:

require 'zip'
require 'stringio'

def generate_multi_letter(template, letterName, params)
  @Document_URL = "#{ENV["API_HOST"]}/api/StateDocument/GenerateDocX/#{template}"
  response = HTTParty.post(@Document_URL,
                           body: params.to_json,
                           headers: { "Content-Type" => "application/json" })

  # Initialize an in-memory zip to hold our files
  output_zip = StringIO.new
  output_zip.set_encoding("BINARY")

  Zip::OutputStream.open(output_zip) do |zos|
    # Read each entry from the API's zip response
    Zip::InputStream.open(StringIO.new(response.body)) do |zis|
      while entry = zis.get_next_entry
        # Optional: Rename the file (customize this as needed)
        new_filename = "#{letterName}_#{entry.name}"
        zos.put_next_entry(new_filename)
        zos.write(zis.read)
      end
    end
  end

  # Reset the stream pointer to the start before reading
  output_zip.rewind

  send_data output_zip.read,
    filename: "#{letterName}.zip",
    type: "application/zip",
    disposition: "attachment"
end

Fixing the "Path Name Contains Null Byte" Error

This error occurs in your second code snippet because you're passing raw binary data (the API response body) to Zip::File.open, which expects a file path string. Binary data often includes null bytes (\0), which are invalid in file paths.

To fix this:

  • Use StringIO to wrap binary data when working with in-memory zip files (like in Option 2 above).
  • Never pass raw binary strings to methods that expect file system paths.

Issues in Your Second Code Snippet

  1. Zip::File.open(response, ...): response is binary data, not a file path—use StringIO instead.
  2. Typo: zipfile.add should be zip.add (your variable is named zip).
  3. Incorrect filename: You're using .docx for a zip file—change it to .zip.
  4. Unnecessary Tempfile: You can handle everything in memory with StringIO instead of writing to temp files.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 00:22:50