I have a method in my CLI app which is giving me an error.
The method is:
def self.deal_page(input, product_url)
self.open_deal_page(input)
deal = {}
html = open(@product_url)
doc = Nokogiri::HTML(html)
data = doc.text.strip
deal[:name] = doc.css("h1").text.strip
deal[:discription] = doc.css(".textDescription").text.strip
@purchase_link = nil
@purchase_link= doc.at_css("div.detailLeftColumn a.success").attr("href")
if @purchase_link.nil?
deal[:purchase] = @product_url
else
deal[:purchase] = @purchase_link
end
deal
end
and the error is:
/home/himachhag-45739/code/popular-deals-from-slickdeals.net-cli/lib/popular_deals/newdeals.rb:54:in `deal_page': undefined method `attr' for nil:NilClass (NoMethodError)
from /home/himachhag-45739/code/popular-deals-from-slickdeals.net-cli/lib/popular_deals/cli.rb:70:in `disply_deal'
from /home/himachhag-45739/code/popular-deals-from-slickdeals.net-cli/lib/popular_deals/cli.rb:49:in `menu'
from /home/himachhag-45739/code/popular-deals-from-slickdeals.net-cli/lib/popular_deals/cli.rb:9:in `call'
from /home/himachhag-45739/code/popular-deals-from-slickdeals.net-cli/bin/popular-deals:10:in `<top (required)>'
from /usr/local/rvm/gems/ruby-2.3.1/bin/popular-deals:22:in `load'
from /usr/local/rvm/gems/ruby-2.3.1/bin/popular-deals:22:in `<main>'
from /usr/local/rvm/gems/ruby-2.3.1/bin/ruby_executable_hooks:15:in `eval'
from /usr/local/rvm/gems/ruby-2.3.1/bin/ruby_executable_hooks:15:in `<main>'
I tried xpath
, at_css
, unless
, if
..else
, but doesn't help. Also, I don't get this error everytime, but I would like to get rid of it.
One way to address this problem is to be a bit paranoid:
@purchase_link = doc.at_css("div.detailLeftColumn a.success").try(:attr, "href")
deal[:purchase] = @purchase_link || @product_url
A couple of things to keep in mind here. In Ruby only nil
and false
are logically false, so it's very rare you need to specifically test nil?
on things. The only case that's necessary is when you want to distinguish between nil
and false
, which as you can imagine is not very often.
So in this case either you hit something with at_css
or you didn't, in which case the try
call doesn't do anything. If it finds something the try
call carries on for one more call. Then you can do an assignment with a simple ||
(or) operator to pick them in priority.
Another thing is since this code is inside a class method, casually using instance variables can be trouble. If things like purchase_link
are only used within this method, remove the @
which makes them persistent.
Another thing to be careful about is how your method is defined as:
def self.deal_page(input, product_url)
That declares an argument product_url
, but inside:
html = open(@product_url)
This references the class instance variable @product_url
which is not the same. You may be calling open
with the wrong variable here.