开发者

Protecting against an undefined chained method

开发者 https://www.devze.com 2023-04-06 12:31 出处:网络
I have a long loop that results in this: csv_code = CSV.generate do |csv| c开发者_JS百科sv << [\"Product ID\",\"Name\", \"Url\"]

I have a long loop that results in this:

csv_code = CSV.generate do |csv|
  c开发者_JS百科sv << ["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

The method uses products 1-17 works great resulting in a url printed. When I get to my 18th record I have problems

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

How can I protect against these undefined events?

url = product.page_url("en_US")


The issue is that a product is nil:

undefined method 'page_url' for nil:NilClass". Solution:

(It has nothing to do with page_url maybe returning nil.)

Make sure product can't be nil: but be wary that this may be a deeper issue. In any case, "fixing" this issue is easy to deal with.

Consider either using a collection restriction (such as Enumerable#reject):

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

The above uses the Symbol#to_proc "Rails magic", but could just as easily have been {|x| x.nil?} as the restriction. The downside is it's not practical to use this for a "no URL" condition per-product although Enumerable#partition could help with that: use the right tool for the job.

Another solution is to expand the conditional check itself:

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

The short-circuit nature of && will ensure page_url is only invoked upon a truthy value (which excludes nil).

I also took the liberty of assuming page_url can't return false as I find this makes the intent more clear.

Happy coding.


Try this:

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

But it's a perf killer.

Are you sure Product.find(18) doesn't return nil ?

Anyway, you could do:

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

精彩评论

暂无评论...
验证码 换一张
取 消