上传.xlsx到AWS S3 Bucket时出现NilClass未定义bucket方法报错
问题根因与修复方案
根因梳理
- S3资源未初始化:你在
upload_file_to_bucket?方法中直接读取@s3_resource实例变量,但该变量仅在调用s3_resource方法时才会初始化,未调用方法直接取变量导致s3赋值为nil,调用bucket方法时触发报错。 - 参数传递顺序错位:
方法定义为def upload_file_to_bucket?(file_name, path, bucket_name),但你在call方法中调用时的参数顺序为upload_file_to_bucket?(bucket_name, file_name, path ),三个参数完全颠倒,方法内拿到的bucket_name实际为未赋值的nil值。 - 桶名逻辑错误:你定义的
BUCKET_NAME方法从未被调用,且方法内错误使用了不存在的s3变量(正确方法名为s3_resource),导致@bucket_name全程为nil。 - 实例变量未赋值:
@file_name、@path两个实例变量从未被赋值,调用时传入的均为nil,因此报错日志中文件名、桶名均显示为空。
修复代码
attr_reader :year, :month, :data, :bucket_name def initialize(year:, month:, data:) @year = year @month = month @data = data # 初始化时就确定桶名,避免后续传参混乱 @bucket_name = 'textract-console-eu-central-1-3469d743-084a-020378550' end def call REPORTS.each do |report| data = generate_report_data(report) tmp_path = report_tmp_path(report) save_report_to_file(data: data, path: tmp_path) # 修正参数顺序,传入正确的文件名、路径、桶名 upload_file_to_bucket?(report, tmp_path, bucket_name ) end end def generate_report_data(report) report_class = "Accounting::Datev::Reports::#{report.to_s.camelize}".constantize report_class.new(year: year, month: month).call end def save_report_to_file(data:, path:) prepare_dir(path) Accounting::Datev::Utils::ExcelGenerator.new(data: data, path: path).call end def s3_resource @s3_resource ||= ::Aws::S3::Resource.new(access_key_id: Settings.aws_pair&.app_key_id, secret_access_key: Settings.aws_pair&.app_secret_key, region: Settings.aws_pair&.s3_region) end def upload_file_to_bucket?(file_name, path, bucket_name) # 直接调用s3_resource方法,确保实例变量已初始化 s3 = s3_resource # 修正object的key,不要用本地路径,改为你想要存在S3上的路径 obj = s3.bucket(bucket_name).object("reports/#{year}/#{month}/#{file_name}.xls") obj.upload_file(path) true rescue StandardError => e puts "Error while uploading the file '#{file_name}' to the bucket '#{bucket_name}': #{e.message}" end def report_tmp_path(report) "/tmp/reports/#{year}/#{month}/#{report}.xls" end def prepare_dir(path) dir = File.dirname(path) FileUtils.mkdir_p(dir) end
额外注意点
- 原代码中S3对象的key写死为
/tmp/test.xls,会导致所有上传的文件都覆盖同一个文件,已在修复代码中调整为按年月和报表名区分的路径。 - 不要直接读取带
@的实例变量来获取懒加载的资源,一定要调用对应的方法确保资源已初始化。
内容的提问来源于stack exchange,提问作者cbln1
相关产品推荐
相关产品推荐

