Rails 6如何读取/tmp目录下生成的CSV文件并通过API发送
解决方案
你当前代码的核心问题是save_csv_to_tmp方法创建临时文件后没有返回文件路径,且Tempfile.create生成的文件会自动在自定义文件名后追加随机字符防重名,硬编码文件名匹配根本找不到目标文件,按以下步骤改即可:
第一步:改造临时文件生成方法
让方法直接返回生成文件的完整路径,方便后续逻辑调用:
def save_csv_to_tmp # 注意:非Rails环境第二个参数建议写绝对路径'/tmp',Rails环境可替换为Rails.root.join('tmp') file = Tempfile.create(["nb_administrateurs_par_mois_#{date_last_month}", '.csv'], '/tmp') file << generate_csv file.close file.path # 返回文件完整路径 end
第二步:实现文件读取+API上传逻辑
在perform方法中拿到文件路径,校验合法性后构造上传请求,最后记得清理临时文件避免占磁盘:
require 'net/http' require 'uri' def perform(*args) csv_path = save_csv_to_tmp # 前置校验,避免文件生成失败导致后续流程无意义执行 raise "临时CSV文件生成失败,路径不存在:#{csv_path}" unless File.exist?(csv_path) # 替换为你的目标API地址 api_uri = URI.parse("https://your-target-api-endpoint/upload") request = Net::HTTP::Post.new(api_uri) # 按需添加请求头,比如认证信息 # request["Authorization"] = "Bearer your_api_token" # 构造multipart格式的文件上传表单,字段名按接口文档要求调整 form_params = [ [ "csv_file", File.open(csv_path, "r"), { filename: File.basename(csv_path), content_type: "text/csv" } ] # 可追加其他接口要求的普通参数,例:["report_month", date_last_month.to_s] ] request.set_form(form_params, "multipart/form-data") # 发起请求 http_options = { use_ssl: api_uri.scheme == "https" } response = Net::HTTP.start(api_uri.hostname, api_uri.port, http_options) do |http| http.request(request) end # 处理响应,按需加日志或者失败重试逻辑 raise "CSV上传失败,响应码:#{response.code},响应内容:#{response.body}" unless response.code.to_i.between?(200, 299) ensure # 无论流程成功失败,最终删除临时文件,避免/tmp目录堆积垃圾文件 File.delete(csv_path) if defined?(csv_path) && File.exist?(csv_path) end
注意避坑
- 不要硬编码文件名去/tmp目录搜索:临时文件带随机后缀,硬编码100%匹配失败,必须拿到创建时返回的真实路径
- 临时目录路径别写错:写相对路径
'tmp'会从脚本运行的当前工作目录找文件夹,生产环境建议直接写绝对路径'/tmp'避免路径找不到 - 不要依赖Tempfile的自动清理机制:CRON是常驻进程,自动回收触发时机不可控,手动在ensure块删文件最稳妥
- 文件上传前必须做存在性校验:定时任务无人工值守,前置校验抛错方便接告警,比静默失败好排查
内容的提问来源于stack exchange,提问作者Kara
相关产品推荐
相关产品推荐

