Rails NoMethodError в цикле, когда метод существует - PullRequest
1 голос
/ 16 апреля 2010

Добрый день всем.

У меня возникла небольшая проблема с запуском скрипта в моей производственной среде, хотя он отлично работает на моем компьютере разработчика. Я проверил, что все необходимые драгоценные камни и тому подобное имеют одинаковую версию.

Следует отметить, что скрипт предназначен для запуска с помощью команды 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

Возвращает правильное значение, нет проблем. Так что же происходит?

Это на рельсах v 2.3.5, на обеих машинах.

Спасибо за любую помощь

Ответы [ 2 ]

3 голосов
/ 16 апреля 2010

Вы выполняете все циклы 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

Но это все равно больше похоже на ассоциацию. Поэтому вы можете захотеть использовать методы ассоциации для дальнейшей очистки.

0 голосов
/ 16 апреля 2010

Очевидно, что вы звоните nil.subject, поэтому Deal.find возвращает ноль в производственном коде. В вашем тестовом примере рассматривается только один конкретный объект Market, но общий случай просматривает объекты Market. Ваш код должен обрабатывать не найти currentDeal для объекта Market

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...