Sidekiq Worker报错‘no implicit conversion of Symbol into Integer’求助
问题分析与解决方案
错误原因
你遇到的no implicit conversion of Symbol into Integer错误,核心问题出在参数传递和文件处理逻辑上:
- 直接传递完整的
params对象给Sidekiq Worker:Rails的ActionDispatch::Http::UploadedFile(上传文件对象)无法被Sidekiq序列化(Sidekiq仅支持JSON兼容的数据类型),序列化后参数结构异常,导致你在Worker中用符号键访问时,实际访问的是数组,触发类型转换错误。 - 临时文件生命周期问题:请求结束后Rails会自动删除上传的临时文件,Worker运行时根本无法读取到原文件。
- 异常捕获被注释:无法记录完整错误信息,排查难度增大。
修复步骤
1. 修改控制器代码:正确传递参数并保存上传文件
不要直接传递整个params,先将上传文件保存到永久位置,再提取必要参数传递给Worker:
def create # 保存上传文件到永久目录 uploaded_file = params[:coupons_import][:file] upload_dir = Rails.root.join('public', 'coupon_uploads') FileUtils.mkdir_p(upload_dir) # 确保目录存在 file_path = upload_dir.join(uploaded_file.original_filename) File.open(file_path, 'wb') { |f| f.write(uploaded_file.read) } # 提取需要的参数,排除无法序列化的文件对象 worker_params = params[:coupons_import].permit( :product, :percent, :amount, :promo_name, :promo_desc, :usage_limit, :starts_at, :expires_at, :option_values ).to_h worker_params[:file_path] = file_path.to_s CouponsImportWorker.perform_async(worker_params) @status = Spree.t('coupons_import.in_progress') flash[:notice] = "CSV processing is in progress. You will be notified upon completion." redirect_back fallback_location: spree.admin_promotions_path end
2. 修改Worker代码:读取永久文件并修复参数访问
调整Worker逻辑,使用保存后的文件路径,同时恢复异常捕获:
require 'csv' require 'json' class CouponsImportWorker include Sidekiq::Worker def perform(worker_params) Rails.logger.info("Worker running with params: #{worker_params}") products = [] worker_params[:product].split(',').each do |product_id| products << Spree::Product.find(product_id) end filename = worker_params[:file_path] Rails.logger.info("Reading file: #{filename}") csv_table = CSV.parse(File.read(filename), headers: true, col_sep: ';') codes = csv_table.map(&:to_h).map { |e| e['code'] } percent = worker_params[:percent].to_i amount = worker_params[:amount].to_d if percent > 0 || amount > 0 codes.each do |code| promotion = Spree::Promotion.create( name: worker_params[:promo_name], description: worker_params[:promo_desc], match_policy: 'all', usage_limit: worker_params[:usage_limit], starts_at: worker_params[:starts_at], expires_at: worker_params[:expires_at], code: code, store_ids: 1 ) if amount > 0 promotion.promotion_actions << Spree::Promotion::Actions::CreateAdjustment.create( calculator: Spree::Calculator::FlatRate.new(preferred_amount: amount) ) else promotion.promotion_actions << Spree::Promotion::Actions::CreateItemAdjustments.create( calculator: Spree::Calculator::PercentOnLineItem.new(preferred_percent: percent) ) end if worker_params[:option_values].blank? create_promotion_rule(promotion, products) else create_promotion_option_value_rule(promotion, products, worker_params[:option_values]) end end end Rails.logger.info("CSV processing completed") ActionCable.server.broadcast('coupons_channel', message: 'CSV processing completed.') # 可选:处理完后删除临时文件 File.delete(filename) if File.exist?(filename) rescue StandardError => e Rails.logger.error("CouponsImportWorker error: #{e.message}") Rails.logger.error(e.backtrace.join("\n")) # 可选:添加错误通知,比如发邮件给管理员 end private def create_promotion_rule(promotion, products) rule = Spree::Promotion::Rules::Product.create(promotion: promotion) rule.products = products rule.save! end def create_promotion_option_value_rule(promotion, products, option_value) Spree::Promotion::Rules::OptionValue.create( promotion_id: promotion.id, type: 'Spree::Promotion::Rules::OptionValue', preferences: { eligible_values: { products.last.id => [option_value] }, match_policy: 'any' } ) end end
3. 额外优化点
- 确保
public/coupon_uploads目录有写入权限,可通过命令创建:mkdir -p public/coupon_uploads && chmod 755 public/coupon_uploads create_promotion_option_value_rule中仅使用products.last.id,如果业务需要关联多个产品的选项值,需调整该逻辑- 可添加文件重命名逻辑,避免同名文件覆盖
内容的提问来源于stack exchange,提问作者Abhishek Panda
相关产品推荐
相关产品推荐

