NoMethodError: undefined method `+' for nil:NilClass for variable in private method
NoMethodError: undefined method `+' for nil:NilClass for variable in private method
您好,我有一项服务 class 从 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 中,局部变量从对它们的赋值被 解析 (未执行)的那一刻开始定义。
由于您要分配给 attempt
,Ruby 将使 attempt
成为 hubspot_record
的局部变量。但是,由于它没有被初始化,它的计算结果将是 nil
.
attempt += 1
等同于
attempt = attempt + 1
并且由于 attempt
未初始化并求值为 nil
,这实际上是在求 nil + 1
.
如果您想使用属性 reader 方法,您必须向 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
Link Ruby 2.7 更新:https://blog.saeloun.com/2019/12/24/ruby-2-7-allows-calling-a-private-method-with-self.html
您好,我有一项服务 class 从 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 中,局部变量从对它们的赋值被 解析 (未执行)的那一刻开始定义。
由于您要分配给 attempt
,Ruby 将使 attempt
成为 hubspot_record
的局部变量。但是,由于它没有被初始化,它的计算结果将是 nil
.
attempt += 1
等同于
attempt = attempt + 1
并且由于 attempt
未初始化并求值为 nil
,这实际上是在求 nil + 1
.
如果您想使用属性 reader 方法,您必须向 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
Link Ruby 2.7 更新:https://blog.saeloun.com/2019/12/24/ruby-2-7-allows-calling-a-private-method-with-self.html