Вы выполняете все циклы 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, вам нужно настроить проверки, чтобы теперь можно было сохранять Market без 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
Ruby всегда будет возвращать результат последнего выражения в методе, а искатель условий на основе очистит этот запрос совсем немного.
def currentDeal
marketTime = self.convertToTimeZone(Time.new)
Deal.find(:first, :conditions => ["start_time > ? AND market_id = ? AND published = ?", marketTime, marketTime, id, true])
end
Но это все равно больше похоже на ассоциацию. Поэтому вы можете захотеть использовать методы ассоциации для дальнейшей очистки.