2010-04-16 36 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