【问题标题】:NoMethodError: undefined method `+' for nil:NilClass for variable in private methodNoMethodError:未定义的方法“+”用于 nil:NilClass 用于私有方法中的变量
【发布时间】:2021-02-28 19:00:01
【问题描述】:

您好,我有一个从 Hubspot 提取信息的服务类。

module HubspotApi
  class CompanyImporter < ApplicationService
    MAX_RETRIES = 3

    def initialize(company_vid)
      @company_vid = company_vid
      @attempt = 0
    end

    def service_body
      imported_profile
    end

    private
 
    attr_reader :company_vid, :attempt

    def imported_profile
      ## load hubspot record over here and take other actions
    end

    def hubspot_record
      @hubspot_record ||= Hubspot::Company.find_by_id(company_vid.to_i)
    rescue Hubspot::RequestError
      if (attempt += 1) <= MAX_RETRIES
        sleep 2**attempt
        retry
      else
        @messages << 'Raise some hubspot error'
      end
    end
  end
end

我尝试使用不正确的 company_vid 调用它,以确保重试正常工作,但我不断收到错误消息:

NoMethodError: undefined method `+' for nil:NilClass from `rescue in hubspot_record'
Caused by Hubspot::RequestError: Response body: {"status":"error","message":"resource not found"}

我不确定我是否在这里放屁,但我无法确定这里的错误,因为应该定义变量

【问题讨论】:

    标签: ruby-on-rails ruby ruby-on-rails-5


    【解决方案1】:

    在 Ruby 中,从对局部变量的赋值被解析(不执行)的那一刻起就定义了局部变量。

    由于您分配给attempt,Ruby 会将attempt 设为hubspot_record 的局部变量。但是,由于它没有被初始化,所以它会评估为nil

    attempt += 1
    

    等价于

    attempt = attempt + 1
    

    由于attempt 未初始化并计算为nil,这实际上是在计算nil + 1

    如果你想使用属性读取器方法,你必须让 Ruby 清楚你打算发送消息而不是访问局部变量。有两种方法可以做到这一点:局部变量不能有接收者,局部变量不能有参数列表。所以,如果你添加其中任何一个,Ruby 就会知道它是消息发送而不是局部变量:

    attempt()
    self.attempt
    

    其中任何一个都会让 Ruby 清楚您打算调用 HubspotApi::CompanyImporter#attempt 方法。

    但是,这仍然行不通,因为您正在尝试分配给并且您实际上没有属性编写器,因此您的下一条错误消息将类似于

    NoMethodError: undefined method `attempt=' for HubspotApi::CompanyImporter
    

    在 Ruby 2.7 之前解决这个问题的方法是:

    attr_reader :attempt 更改为attr_accessor :attempt

    def hubspot_record
      @hubspot_record ||= Hubspot::Company.find_by_id(company_vid.to_i)
    rescue Hubspot::RequestError
      if (self.attempt = attempt + 1) <= MAX_RETRIES ## This was fixed in Ruby 2.7 but for earlier versions you need to read using self and write directly.
        sleep 2**attempt
        retry
      else
        @messages << 'Raise some hubspot error'
      end
    end
    

    Ruby 2.7 更新链接:https://blog.saeloun.com/2019/12/24/ruby-2-7-allows-calling-a-private-method-with-self.html

    【讨论】:

    • 是的,你是对的!我将其更改为attr_accessor,但即使这样还不够,因为我收到了一个错误,private method attempt' 称为`
    • 您使用的是 ruby​​ 2.7 吗?我在上面编辑了您的答案以添加我的最终解决方案
    • 不,我没有使用 Ruby 2.7。如果问题没有指明 Ruby 的特定版本,则通常假定提问者使用的是最新版本,目前为 3.0.0。
    • 是的,完全公平。当我最初问这个问题时,我只是没有意识到它可能与我的 ruby​​ 版本有关。谢谢你的详细回复,虽然很清楚:)
    猜你喜欢
    • 1970-01-01
    • 2015-10-05
    • 1970-01-01
    • 2012-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-17
    • 2014-03-16
    相关资源
    最近更新 更多