Angular前端上传文件至Rails+Dragonfly+OCI时保存失败问题
问题:Angular上传文件后,Rails中Dragonfly无法将文件上传至OCI对象存储
我在Angular中实现文件上传,将参数存入imageData和imageContent变量传给Rails后端。在Rails控制器中尝试用这些参数创建临时文件,并赋值给Dragonfly的logo访问器属性,但保存记录时,文件并未上传到OCI对象存储。不过在Rails控制台中直接测试OCI对象存储的上传功能是正常的。
Dragonfly访问器配置
dragonfly_accessor :logo do storage_options do |attachment| { path: "brand_logos/" } end end
Rails控制器处理代码
decoded_data = Base64.decode64(params[:brand][:logo][:imageData]) # json parameter set in directive scope file_name = params[:brand][:logo][:imagePath] File.open(file_path, 'wb+') { |file| file.write(decoded_data) } params[:brand][:logo][:tempfile] = file_path # json parameter set in directive scope
问题原因与修复方案
核心问题是你给Dragonfly的tempfile赋值的是文件路径字符串,但Dragonfly的文件访问器需要的是File对象(或实现IO接口的对象),而非路径字符串。
方案1:使用临时文件对象赋值
decoded_data = Base64.decode64(params[:brand][:logo][:imageData]) file_name = params[:brand][:logo][:imagePath] # 创建带后缀的临时文件,避免格式识别问题 temp_file = Tempfile.new( [File.basename(file_name, '.*'), File.extname(file_name)], Rails.root.join('tmp') ) temp_file.binmode temp_file.write(decoded_data) temp_file.rewind # 将文件指针移到开头,确保Dragonfly能读取完整内容 # 直接给模型属性赋值文件对象,无需修改params @brand = Brand.new(params[:brand].except(:logo)) @brand.logo = temp_file @brand.save! # 清理临时文件 temp_file.close temp_file.unlink
方案2:用StringIO替代物理文件(更高效)
不需要创建本地物理文件,直接用内存中的IO对象传递数据:
decoded_data = Base64.decode64(params[:brand][:logo][:imageData]) file_name = params[:brand][:logo][:imagePath] # 用StringIO包装解码后的数据,模拟文件对象 file_io = StringIO.new(decoded_data) # 给StringIO添加original_filename属性,满足Dragonfly的文件名要求 file_io.class.class_eval { attr_accessor :original_filename } file_io.original_filename = file_name @brand = Brand.new(params[:brand].except(:logo)) @brand.logo = file_io @brand.save!
额外注意事项
- 控制台能正常上传说明OCI存储配置无问题,问题集中在文件对象的传递逻辑上;
- 使用
Tempfile时要记得清理文件,避免服务器磁盘被临时文件占满; - StringIO方式无需磁盘IO,性能更优,推荐优先使用。
内容的提问来源于stack exchange,提问作者Seemab
相关产品推荐
相关产品推荐

