Rails.cache.fetch缓存JSON数组失效,@my_api_data_报NilClass错误
问题分析与解决方案
你的问题核心在于缓存命中时,Rails.cache.fetch的代码块不会执行,导致实例变量@my_api_data_从未被赋值,最终视图调用each时触发nil类错误。
修复后的代码
def index api_statuses_ end def api_statuses_ # 把缓存的结果直接赋值给实例变量 @my_api_data_ = Rails.cache.fetch('api_response_m_', expires_in: 3.minutes) do mypairs = ['ticker1','ticker2', 'ticker3', 'ticker4', 'ticker5', 'ticker6', 'ticker7', 'ticker8', 'ticker9', 'ticker10'] my_api_data = [] base_url = 'https://myserver.com/ticker/' mypairs.each do |item| uri = URI(base_url + item) response = Net::HTTP.get(uri) begin myresult = JSON.parse(response) rescue JSON::ParserError # 解析失败时给默认值,避免推入nil污染数组 myresult = { error: 'Failed to parse response' } end my_api_data.push(myresult) end # 块最后必须返回要缓存的数据,这里是我们组装好的数组 my_api_data end end
为什么原来的代码会失效?
- 缓存逻辑的本质:
Rails.cache.fetch的工作机制是:如果缓存键存在,则直接返回缓存值,不会执行代码块;只有缓存键不存在时,才会执行块内代码,并把块的返回值存入缓存。 - 实例变量的作用域问题:你原来的代码是在块内给
@my_api_data_赋值,但当缓存命中时,块根本不会运行,@my_api_data_始终是nil,视图自然无法调用each方法。 - 缓存内容的误区:你之前尝试在块末尾返回
@my_api_data_,但没有把fetch的返回值赋值给实例变量,所以缓存的数据根本没有传递到视图中。
额外优化建议
- 修正缓存键拼写:把
api_repsonse_m_改成api_response_m_(少写了一个s),避免后续维护时混淆。 - 用局部变量替代块内实例变量:块内使用局部变量(比如
my_api_data)比实例变量更安全,不会意外污染控制器的其他实例变量。 - 完善错误处理:JSON解析失败时,不要空着
rescue块,至少给个默认值,避免数组中混入nil导致后续视图逻辑出错。 - 考虑更优雅的HTTP客户端:Net::HTTP比较繁琐,可以尝试
Faraday或HTTParty,简化API请求和错误处理。
内容的提问来源于stack exchange,提问作者Vitali Grabovski
相关产品推荐
相关产品推荐

