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

Rails中Sidekiq Worker的API请求重构及NameError报错解决

问题解决与代码重构方案

报错原因

报错undefined local variable or method 'url'是因为bindable_lead_client和post_request方法试图访问perform方法内的局部变量url,但这两个方法的作用域中不存在该变量,导致变量未定义。

推荐重构方案(抽离API客户端类)

将Active Campaign的HTTP请求逻辑抽离为独立服务类,让Worker专注于业务逻辑,代码更整洁且易于维护。

1. 创建Active Campaign客户端服务类

新建app/services/active_campaign_client.rb:

class ActiveCampaignClient
  BASE_URL = Rails.application.credentials.dig(:active_campaign, :url)
  API_KEY = Rails.application.credentials.dig(:active_campaign, :key)

  def initialize
    @http_client = build_http_client
  end

  def update_contact_field(contact_id, field_id, value)
    url = URI("#{BASE_URL}/api/3/contacts/#{contact_id}")
    request = build_put_request(url)
    request.body = JSON.dump(contact: { fieldValues: [{ field: field_id, value: value }] })
    
    response = JSON.parse(@http_client.request(request).read_body).symbolize_keys
    handle_response(response, contact_id, value)
  end

  private

  def build_http_client
    base_uri = URI(BASE_URL)
    http = Net::HTTP.new(base_uri.host, base_uri.port)
    http.use_ssl = true
    http
  end

  def build_put_request(url)
    request = Net::HTTP::Put.new(url)
    request['Accept'] = 'application/json'
    request['Content-Type'] = 'application/json'
    request['api-token'] = API_KEY
    request
  end

  def handle_response(response, contact_id, value)
    if response[:code] == '200'
      Rails.logger.info "Successfully updated contact #{contact_id} with lead id #{value}"
    else
      raise "Error updating contact: #{response[:body]}"
    end
  end
end

2. 重构Worker类

class UpdateLeadIdWorker
  include Sidekiq::Worker

  def perform(ac_id, current_user_id)
    lead = Lead.where(user_id: current_user_id).last
    raise 'Lead not found' unless lead

    field_id = quote_type_to_field_id(lead.quote_type)
    ActiveCampaignClient.new.update_contact_field(ac_id, field_id, lead.lead_id)
  end

  private

  def quote_type_to_field_id(quote_type)
    case quote_type
    when 'renter' then '5'
    when 'home' then '4'
    when 'auto' then '3'
    else raise "Invalid quote type: #{quote_type}"
    end
  end
end

重构优势

  • 单一职责:Worker仅处理业务逻辑(查询Lead、映射字段ID、调用API),HTTP请求逻辑封装在客户端类中,职责清晰。
  • 可复用性:客户端类可在其他Worker或控制器中复用,避免重复代码。
  • 易测试:客户端类可单独测试,Worker的测试只需验证业务逻辑的正确性。
  • 易维护:新增报价类型时,仅需修改quote_type_to_field_id方法,无需改动HTTP请求代码。

快速修复方案(不抽离类)

若暂时不想抽离服务类,可通过将url作为参数传递给方法解决作用域问题:

class UpdateLeadIdWorker
  include Sidekiq::Worker

  BASE_URL = Rails.application.credentials.dig(:active_campaign, :url)
  private_constant :BASE_URL
  API_KEY = Rails.application.credentials.dig(:active_campaign, :key)
  private_constant :API_KEY

  def perform(ac_id, current_user_id)
    lead = Lead.where(user_id: current_user_id).last
    url = URI("#{BASE_URL}/api/3/contacts/#{ac_id}")

    https = bindable_lead_client(url)
    pr = post_request(url)

    data = { contact: { fieldValues: [{ field: quote_type_to_field_id(lead.quote_type), value: lead.lead_id }] } }
    pr.body = JSON.dump(data)
    response = JSON.parse(https.request(pr).read_body).symbolize_keys

    if response.code == '200'
      Rails.logger.info "Successfully updated contact #{ac_id} with lead id #{lead.lead_id}"
    else
      raise "Error creating contact: #{response.body}"
    end
  end

  def bindable_lead_client(url)
    http = Net::HTTP.new(url.host, url.port)
    http.use_ssl = true
    http
  end

  def post_request(url)
    post_request_ = Net::HTTP::Put.new(url)
    post_request_['Accept'] = 'application/json'
    post_request_['Content-Type'] = 'application/json'
    post_request_['api-token'] = API_KEY
    post_request_
  end

  private

  def quote_type_to_field_id(quote_type)
    case quote_type
    when 'renter' then '5'
    when 'home' then '4'
    when 'auto' then '3'
    else raise 'Invalid quote type'
    end
  end
end

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 09:18:26