2010-04-16 18 views
1

美好的一天。当方法存在时循环中的方法NoMethodError

即使在我的开发环境中工作得很好,我也遇到了一些问题,让脚本在我的生产环境中运行。我已经证实所有必需的宝石和这些都是相同的版本。

我应该提到脚本是用脚本/ 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 
 

它返回正确的值,没问题。那么发生了什么?

这是在轨道v 2.3.5,在两台机器上。

感谢所有帮助

+0

我认为你已经在Deal.find调用中重复了marketTime参数。 – Fred 2010-04-16 16:17:33

回答

3

你循环尽管所有Market,在你的生产代码,但你的测试片段只找一个。问题在于你的数据库中有一个MarketcurrentDealnil(它没有与它关联的对象)。

请在您的生产控制台上运行此操作。

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 s都有currentDeal,或者有时他们不这样做。如果Market's应该总是有currentDeal,那么你需要调整你的验证,现在允许市场在没有currentDeal的情况下被保存。但鉴于currentDeal是基于时间的事情,我会认为有些时候没有计划交易,因此currentDeal将返回零。

所以,更可能的是,您需要允许目前的交易为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 

红宝石总是返回最后一个表达式的结果的方法,以及基于已取景器的条件将清理查询不少。

def currentDeal 
    marketTime = self.convertToTimeZone(Time.new) 
    Deal.find(:first, :conditions => ["start_time > ? AND market_id = ? AND published = ?", marketTime, marketTime, id, true]) 
end 

但是,无论如何,这看起来更像是一个关联。所以你可能想使用关联方法来进一步清理这个问题。

0

显然你打电话给nil.subject,所以Deal.find在生产代码中返回nil。您的测试用例只查看一个特定的市场对象,但一般情况下通过市场对象循环。你的代码需要处理没有找到一个市场对象的currentDeal