Защита от неопределенного цепного метода - PullRequest
2 голосов
/ 20 сентября 2011

У меня есть длинный цикл, который приводит к этому:

csv_code = CSV.generate do |csv|
  csv << ["Product ID","Name", "Url"]
  @all_products.each do |product|
      if product.page_url("en_US") != nil
      turl = product.page_url("en_US")
      end
    csv << [product.name,product.d_id, turl]
  end
end

В методе используются продукты 1-17, которые отлично работают, в результате чего печатается URL. Когда я добираюсь до своей 18-й записи, у меня возникают проблемы

Product.find(18) // product found!
product.find(18).page_url("en_US")
NoMethodError: undefined method `page_url' for nil:NilClass

Как я могу защитить от этих неопределенных событий?

url = product.page_url ("en_US")

Ответы [ 2 ]

3 голосов
/ 20 сентября 2011

Проблема в том, что product равно nil:

неопределенный метод 'page_url' для nil: NilClass ". Решение:

(он не имеет ничего общего с page_url возможно , возвращающего nil.)

Убедитесь, что product не может быть nil: но будьте осторожны, что это может быть более глубокой проблемой. В любом случае, "исправить" эту проблему легко.

Рассмотрите возможность использования ограничения коллекции (например, Enumerable # reject ):

@all_products.reject(&:nil?).each do {
   ...
}

Выше используется Symbol # to_proc "Рельсовая магия" , но с такой же легкостью он мог бы быть {|x| x.nil?} как ограничение. Недостатком является то, что это не практичноиспользовать это для условия «нет URL» для каждого продукта, хотя Enumerable # partition может помочь с этим: используйте правильный инструмент для задания.

Другое решение состоит в расширении условной проверкисамо по себе:

if product && product.page_url("en_US")
   # yay
else
   # uhm
end

Характер короткого замыкания && гарантирует, что page_url вызывается только при истинном значении (исключаяnil).

Я также взял на себя смелость предположить, что page_url не может вернуть false, поскольку я нахожу, что это делает цель более ясной.

Удачное кодирование.

2 голосов
/ 20 сентября 2011

Попробуйте:

product.find(18).try(:page_url, "en_US")

Но это просто убийца перфектов.

Вы уверены, что Product.find(18) не вернется nil?

В любом случае, вымог сделать:

url = product.nil? ? "no_url" : product.page_url("en_US")
...