`block in <main>': undefined method `[]' for nil:NilClass (NoMethodError) - ruby-on-rails

I'm trying to load a remote JSON URL to eventually store it in an SQLite3 database.
I am loading the JSON alright (I think) and then looping through it to assign each JSON value to a variable which will then be built into a db.execute statement to store it into the database.
I am getting an error 'block in <main>': undefined method[]' for nil:NilClass (NoMethodError) when I run the code.
The link Undefined method '>' for nil:NilClass <NoMethodError> is full of information but I don't understand what's going on to be honest. I'm wondering if someone can explain to me where I'm going wrong in my understanding.
My code is:
require 'json'
require 'open-uri'
tournament_url = "http://www.pgatour.com/data/r/033/leaderboard-v2.json"
puts tournament_url
leaderboard = JSON.load(open(tournament_url))
no_of_players = leaderboard['leaderboard']['players'].length
puts "The number of players to be loaded is: #{no_of_players}"
data_array = Array.new
for i in 0..no_of_players
current_position = leaderboard['leaderboard']['players'][i]['current_position']
end
If I write any code after the end loop it won't execute.
If had also tried to do a check on the value returned by saying:
if (leaderboard['leaderboard']['players'][i]['current_position'].nil?)
current_position = ""
else
current_position = leaderboard['leaderboard']['players'][i]['current_position']
end

Range 0..no_of_players is inclusive.
You probably want to use exclusive version (note three dots):
0...no_of_players
or:
0..no_of_players-1

.lenth returns the number of array items - so the array position of the last item would be no_of_players.length - 1. Basically you get the error because on the last iteration of the loop you get nil.
Instead I might suggest using .each:
leaderboard['leaderboard']['players'].each do |player|
current_position = player['current_position']
end

Related

undefined method `last' for #<Hash:0x00007f303593d6d8>

trying the below code in a custom sdk in Workato
poll: lambda do |connection, input, last_updated_at|
per_page = 1
last_updated_at = (last_updated_at || input['since']).to_time.utc.iso8601
candidates = get("https://api.stripe.com/v1/customers")
last_updated_at = candidates.last["created"] unless candidates.blank?
Getting an error
undefined method `last' for #Hash:0x00007f303593d6d8 at line:
There is no Hash#last method. Hashes do keep their insertion order, but you should conceptually treat them as unordered. The concept of the "last" element of a Hash simply does not make sense.

Contentful Rails Test if Object is Empty

p entry # <Contentful::Entry[item] id='3oXocy0iJX8ksdfe435RjWjE'>
i = entry.image
p i.present? # true
p i.nil? # false
p i.respond_to?(:url) # true
p i.url # undefined method `url' for nil:NilClass
p i # undefined method `url' for nil:NilClass
I'm pulling an item from Contenful CMS and trying to render it in Rails. My content admin managed to delete the image (the field is actually called "image") on the entry, thereby causing the render to break. The code above is me trying to test for a missing image so I can skip rendering the section and not break my website.
As you can see, this is mindnumbingly insane. Rails says the entry is there (it is), it says it's not nil, then immediately below it throws an error for nil:NilClass.
The last line is probably the most interesting - even if I just try to print or inspect "i" I still get the error as if I'm trying to access the url attribute. I feel like I'm taking crazy pills.

ruby on rails: suddenly failing method

I am not sure how to present my issue best without posting the whole framework.
I have a method duplicate! which should duplicate an object (channel). Usually it works but there is one channel where the method fails and I just don't understand why:
def duplicate!
channel = Channel.new do |c|
c.title = title << ' (copy)'
c.description = description
end
channel.nodes += nodes
playlist.nodes.each { |n| channel.playlist.playlist_items.create(node: n) }
channel
end
As said nearly all channels duplicate without a problem, but now I have one channel which fails to get duplicated:
2.3.0 :002 > channel.duplicate!
NoMethodError: undefined method `playlist_items' for nil:NilClass
from /var/www/app/models/channel.rb:110:in `block in duplicate!'
from /var/www/app/models/channel.rb:110:in `each'
from /var/www/app/models/channel.rb:110:in `duplicate!'
Every Channel has Nodes and a Playlist, the error producing Channel has too.
I don't really understand the error; how can this method fail depended on the object to duplicate?
The reason this is failing is because one of your channels dont have a playlist record. So this line is failing
playlist.nodes.each { |n| channel.playlist.playlist_items.create(node: n) }
for the channel that does not have a playlist record channel.playlist returns nil so when you do channel.playlist.playlist_items you are calling nil.playlist_items, and since nil does not have the method you get an error.
You could just do this instead of making your on duplicate method fyi
copy_of_channel5 = channel5.dup
This will duplicate the object
You could also do this
copy_of_channel5 = channel5.clone
Look here for a details explanation of the difference between the 2
Trouble Shooting*
Go to your gem file and add this line gem 'pry'
Run bundle
Replace this line playlist.nodes.each { |n| channel.playlist.playlist_items.create(node: n) } with the below code.
playlist.nodes.each {|n| binding.pry}
once the execution console pauses type in the console channel.playlist then press enter and post the output.

Rails 3 - NoMethodError: undefined method for nil:NilClass in each Iteration

I'm iterating over an array of instances of a Rails model. Here is my code:
product_details.each do |product_detail|
product_detail.label = Backend::ProductGroup.where(product_group_number: product_detail.product_group).first.label
end
The attribute 'label' from 'product_detail' isn't an attribute from my Rails ActiveRecord model. I added it with attr_accessor in my class definition. I did this, because I wanted to add this attribute dynamically, only when I need to do this. When I ran the code without the 'each' iteration in my rails console it works just fine. But when I execute the above code I get the following error message:
NoMethodError: undefined method 'label' for nil:NilClass
Did I do something obviously wrong?
Many thanks in advance.
You likely have several product_detail items that have no matching product_group. So calling .first on the empty collection returns nil. To get around the error, you can test if the product_group was found before proceeding:
product_details.each do |product_detail|
product_group = Backend::ProductGroup.where(product_group_number: product_detail.product_group).first
product_detail.label = product_group.label if product_group
end
You can also do this more efficiently like so:
group_labels = BackEnd::ProductGroup.
where(product_group_number: product_details.map(&:product_group)).
inject({}){|m, g| m[g.product_group_number] = g.label; m}
product_details.each do |product_detail|
product_detail.label = group_labels[product_detail.product_group]
end
This will result in a single database call to grab all related groups, and put the labels in a keyed hash for easy discovery and assignment.

How to catch an "undefined method `[]' for nil:NilClass" error?

I get an nested array from facebook via omniauth and wanna check if it's empty?/nil?/exists?
the depending line looks like:
unless omniauth['extra']['raw_info']['location']['name'].nil?
This should check if this part of the array is empty or exists.
But always this error was thrown:
undefined method `[]' for nil:NilClass
Do I check arrays wrong?
I tried it with "has_key" "nil?" "empty?" "exists?" "blank?"
But no one of these works!
Please help me, many thanks in advance!
Ideally you should check each nested level to see if it is nil, however, this will also work.
unless (omniauth['extra']['raw_info']['location']['name'] rescue nil).nil?
You can also rescue the NoMethodError specifically.
This error is raised because one of the hash values in the chain of omniauth['extra']['raw_info']['location']['name'].nil? returns nil and it is not the last call ['name'].
If for example omniauth['extra']['raw_info'] returns nil, you're actually trying to call nil['location'] which raises an error in ruby.
You can catch this error simply:
res = omniauth['extra']['raw_info']['location']['name'].nil? rescue true
unless res
#your code here
end
Please notice that the code block above will fill the variable res with true if the ['name'] hash value is nil or any other hash value in the chain returns nil.
A bit late to the party, but, as pointed in this answer, Ruby 2.3.0 introduced a new method called dig, which would return nil if one of the chained keys is nil. Your omniauth auth hash could then be presented as:
omniauth = {
...
"extra"=>{ "raw_info"=>
{ "location"=>"New York",
"gravatar_id"=>"123456789"}}
...
}
omniauth.dig('extra',
'raw_info',
'location',
'name',
'foo',
'bar',
'baz') #<= nil

Resources