美好的一天。
我在生产环境中运行脚本遇到了一些问题,即使它在我的开发箱上工作得很好。我已经确认所有必需的宝石都是相同的版本。
我应该提一下脚本是用script / runner命令运行的。
这是我正在尝试做的超级浓缩版本,围绕着被打破的部分:
def currentDeal
marketTime = self.convertToTimeZone(Time.new)
deal = Deal.find(:first, :conditions => ["start_time ? AND market_id = ? AND published = ?", marketTime, marketTime, self.id, 1])
return deal
end
markets = Market.find(all)
markets.each do |market|
deal = market.currentDeal
puts deal.subject
end
现在convertToTimeZone是一个附加到模型的方法。所以,正如所述,这个代码在我的开发机器上运行得很好。但是,尝试在我的生产计算机上运行它会导致:
undefined method `subject' for nil:NilClass (NoMethodError)
但是,如果我进入生产箱的控制台并执行此操作:
def currentDeal
marketTime = self.convertToTimeZone(Time.new)
deal = Deal.find(:first, :conditions => ["start_time ? AND market_id = ? AND published = ?", marketTime, marketTime, self.id, 1])
return deal
end
market = Market.find(1)
deal = market.currentDeal
puts deal.subject
它返回正确的值,没问题。那是怎么回事?
这是在两台机器上的rails v 2.3.5上。
感谢您的帮助
答案 0 :(得分:3)
您正在循环使用生产代码中的所有Market
,但您的测试代码段仅查找一个。问题是您数据库中的Market
之一currentDeal
nil
(没有与之关联的对象)。
改为在生产控制台上运行。
markets = Market.find(all)
markets.each do |market|
deal = market.currentDeal
if deal
puts deal.subject
else
puts "NO currentDeal for Market with id: #{market.id}"
end
end
这将在没有Market
的情况下确切地告诉您哪个currentDeal
记录正在爆炸。
所以问题是如何修复它?要么所有Market
都要currentDeal
,要么有时候没有,这没关系。如果Market应该总是有一个currentDeal,那么你需要调整你的验证,现在允许在没有currentDeal的情况下保存Market。但鉴于currentDeal是基于时间的事情,我认为有时没有安排任何交易,因此currentDeal
将返回nil。
因此,更有可能的是,您需要允许当前交易为nil
。您的测试代码不会这样做。它询问市场的交易,然后是交易的主题。如果市场返回nil
交易,那么您会立即询问nil
该主题,并且您获得了例外,因为nil
没有名为subject
的方法。一些简单的方法来保护代码:
deal = market.currentDeal
# simple if
if deal
puts deal.subject
end
# rails try method returns nil if the receiver is nil
# or executes the method if the object supports it
puts deal.try(:subject)
# ternary
puts deal ? deal.subject : "NO DEAL!"
# conditional execution
puts deal && deal.subject
最后,红宝石小费。这种方法比它需要的更复杂。
def currentDeal
marketTime = self.convertToTimeZone(Time.new)
deal = Deal.find(:first, :conditions => ["start_time ? AND market_id = ? AND published = ?", marketTime, marketTime, self.id, 1])
return deal
end
Ruby将始终在方法中返回最后一个表达式的结果,并且基于条件的查找程序将清理该查询。
def currentDeal
marketTime = self.convertToTimeZone(Time.new)
Deal.find(:first, :conditions => ["start_time > ? AND market_id = ? AND published = ?", marketTime, marketTime, id, true])
end
但无论如何,这看起来更像一个协会。因此,您可能希望使用关联方法进一步清理它。
答案 1 :(得分:0)
显然,您正在调用nil.subject
,因此Deal.find在生产代码中返回nil。您的测试用例仅查看一个特定的Market对象,但是一般情况通过Market对象循环。您的代码需要处理没有为Market对象找到currentDeal