2010-04-16 2 views
1

모두 좋은 하루였습니다.레일 메서드가있을 때 루프에 NoMethodError가 발생했습니다.

내 개발 환경에서 스크립트를 실행하는 데 약간의 문제가 있습니다. 비록 내 dev 환경에서 제대로 작동하지만. 필요한 모든 보석 등이 동일한 버전인지 확인했습니다.

이 스크립트는 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 모델에 부착하는 방법입니다 : 여기

가 생겼 부분을 중심으로 내가 할 노력하고있어의 슈퍼 응축 버전입니다. 그래서,이 코드는 내 dev 컴퓨터에서 잘 작동합니다. 그러나 내 생산 기계 결과에 그것을 실행하려고 : 그러나 내가 생산 상자의 콘솔에 가면

 

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에 있습니다. 당신은 당신의 생산 코드에 대한 모든 Market의 불구하고 반복되지만, 테스트 조각 하나만을 찾고

+0

Deal.find 호출에서 marketTime 인수를 복제 한 것 같습니다. – Fred

답변

3

어떤 도움

감사합니다. 문제는 데이터베이스에있는 Market 중 하나에 currentDealnil (연결된 개체가 없음) 인 것입니다.

대신 프로덕션 콘솔에서 실행하십시오. Market 레코드가 currentDeal없이 폭발하는

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이 있어야하며, 그렇지 않은 경우도 있습니다. 괜찮아요. 마켓에 항상 currentDeal이 있어야한다면, 현재 마켓이 currentDeal없이 저장되도록 검증을 조정해야합니다. 그러나 currentDeal이 시간 기반의 것임을 감안할 때 거래가 예정되어 있지 않으므로 currentDeal은 무효로 돌아갈 것입니다.

따라서 현재 거래가 nil 일 수 있도록 허용해야합니다. 테스트 코드가이를 수행하지 않습니다. 그것은 시장에 거래를 요구하고, 거래가 그 대상이된다. 시장이 nil 거래를 반환하면 nil에 대해 즉시 문의하십시오. 따라서 nil에는 subject이라는 메서드가 없기 때문에 예외가 발생합니다. 당신의 코드를 보호 nil을하기 위해 몇 가지 간단한 방법 :

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을 반환합니다. 테스트 케이스는 하나의 특정 Market 오브젝트 만보고 있지만 일반적인 경우는 Market 오브젝트를 통해 루프됩니다. 귀하의 코드는 Market 객체에 대한 currentDeal을 찾지 못하게 처리해야합니다.

관련 문제