Check for nil gives error - ruby-on-rails

I have this line in my controller:
user = User.any_of({:user_name => login}, {:email => login})
if user.nil?
# ...
elsif user.legacy_password.nil?
And it creates this error:
undefined method `legacy_password' for []:Array
Why would this happen? the user object is supposed to be nil. At least that is what the debugger said.

I'm assuming your any_of method returns an array of results, not a single result. You probably want to add .first to the end of it, which will give you either a User record, or nil if any_of returned an empty array.
user = User.any_of({:user_name => login},{:email => login}).first

Looks like you are using mongoid (#any_of) and it's returning an array.
The error is because you are calling legacy_password on an array, but I assume it is defined on the User model.

Related

Undefined method `to_date' for nil:NilClass

I tried to put a try method for fixing the error,but it won't still want it to work out.
If I wasn't specific enough, please let me know.
How to fix this error?
Generally speaking, if you see a message saying "Undefined method 'foo' for nil:NilClass" it means that you are calling the method "foo" on an object whose value is nil. Like everything in Ruby, "nil" is an object, and it's class is NilClass - that's what the message means.
In this case, the object in question is params[:date], since that is what you are calling the .to_date method on. params is a Hash (well, a hash-like object at least), and with a hash, if you call a key on it and it doesn't have that key, it returns nil.
So, your problem is that you are expecting params[:date] to have something in it, and it doesn't.
Maybe you should handle situations when the parameter :date hasn't been given. Maybe use a default value like this:
if params.has_key?(:date)
date = DateTime.parse(params[:date])
else
date = DateTime.now
end
po_id = CardApplicationTrack.where(
:batched_for_payment => true,
:admin_user_id => params[:admin_user_id].to_i,
:created_at =>
date.beginning_of_day ..
date.end_of_day
).map { |cat| cat.processing_order_id }
Or tell the user that you didn't enter a date if params[:date] is missing.
You can also use .try method, try following.
date = params[:date].try(:to_date) || DateTime.now
po_id = CardApplicationTrack.where(
batched_for_payment: true,
admin_user_id: params[:admin_user_id].to_i,
created_at: date.beginning_of_day..date.end_of_day
).pluck(:processing_order_id)
This will not throw error.
params[:date].try(:to_date).try(:end_of_day)

Checking for nil result set before viewing

I've been reading Checking for nil in view in Ruby on Rails but I'm struggling to implement the marked solution.
I want to only load a graph in my View if a result set is not nil.
Controller:
#statistics = # ...my ActiveRecord query...
Helper:
def show_stats(statistics)
if statistics.pluck(:count)
image_tag(Gchart.line :size => '640x260',
:stacked => false,
:title => '',
:data => [statistics.pluck(:count)],
:legend => ['Stats'],
:bar_colors => ['3300CC', '3399FF'],
:axis_with_labels => ['y'])
end
end
View (HAML):
= show_stats(#statistics)
Currently when there are no statistics, I get an error. I want the View to not render the graph if there are no statistics. What am I doing wrong in the helper?
Error:
undefined method `-' for nil:NilClass
on the line where I call the helper.
if i understand correctly statistics.pluck(:count) will always return an array consisting of values of count attribute for each record found.
in ruby empty array evaluates to true, you might try to rewrite that if line like this:
if statistics.pluck(:count).any?
in fact it's good idea to cache that value and not fetch it from db again few lines below:
if (counts = statistics.pluck(:count)).any?
...
:data => [counts]
...
end
also i assume :data option wants array of values and not array of array of values so the final version would be:
if (counts = statistics.pluck(:count)).any?
...
:data => counts
...
end
P.S. if you still have an error - please share a full backtrace with us, knowing only "undefined method" doesn't tell much
Why not check for #statistics in your view like follows:
= show_stats(#statistics) if #statistics
Did you try this?
= show_stats(#statistics) unless #statistics.nil?

Where method if condition is false

Does it return empty array or nil if condition is false?
For example:
#result=Result.where(:test_id=>test_id, :user_id => current_user.id).first
if there is no result with such test_id and user_id.
I just don't get, I thought first option, but this returns nil.
Your variable is constructed in two parts, the first part returns an ActiveRecord::Relation (which is essentially an array):
#result_array = Result.where(:test_id=>test_id, :user_id => current_user.id)
> #result_array.class
=> ActiveRecord::Relation
which is empty (shows as []) if there are no results.
The second returns the first item, or (if it's the empty array) nil:
> (1..10).first
=> 1
> [].first
=> nil
#first_or_nil = #result = #result_array.first
I recommend typing these type of commands in the rails console to see what the results.
For your problem you may use like this code.
#result=Result.where(:test_id=>test_id).(:user_id => current_user.id).first
Thy to use #bang with method .first!
For example:
#result=Result.where(:test_id=>test_id, :user_id => current_user.id).first!
It should return the first element whit ruby will meet in table "results".
It should help.
You can also use this simple query...
#result=current_user.results.find_by_test_id(:test_id)

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

Rails will return an object successfully, but complains that the object is NIL if I try to access an attribute of it

I am trying to populate a nested field, product_name, it an Item.
In my Item model:
class Item < ActiveRecord::Base
attr_writer :product_name
belongs_to :order
belongs_to :product
def product_name
#Product.find_by_id(self.product_id) #=> returns the product object
#self.product #=> returns the product object
#Product.find_by_id(self.product_id).name #=> complains that 'name' is being called on nil
#self.product.name #=> complains that 'name' is being called on nil
#"foooobar" #=> returns "foooobar"
end
end
Each of those commented lines behaves as described.
What I don't get is, how can something return an object successfully, but then complain that the object is nil when you access an attribute of it?
Here is the whole error:
NoMethodError in Orders#edit
Showing app/views/orders/_form.haml where line #18 raised:
undefined method `name' for nil:NilClass
Extracted source (around line #18):
17: = item.hidden_field :product_id
18: = item.text_field :product_name, :class => 'auto_complete_input'
19: = item.text_field :quantity, :size => 2
Thanks
You may want to take a look at the andand plugin at http://github.com/raganwald/andand.
Basically, what it does is handle the errors that may arise from trying to call a method on another that has the possibility of being nil.
Based solely on your example:
Product.find_by_id(self.product_id).name #=> complains that 'name' is being called on nil
An implementation of andand would look like:
Product.find(self.product_id).andand.name
And even if the first statement, Product.find(self.product_id), returns nil it would no longer fire the undefined method on nil error.
PS:
Again, based solely on your code, I can see that you're reproducing the functionality generated by using the :belongs_to association. Essentially, what it means is that you can use:
self.product
insead of:
Product.find_by_id(self.product_id)
It sounds like you're asking a really general question. If you're asking a totally different question than I'm hearing, ignore this. :)
Yes, Ruby is successfully returning an object, and the object is nil. In Ruby, a method can return any value, and nil is just another value that a method can return. Those statements are probably doing a query that isn't returning any results, so the method returns nil instead of the object you are expecting.
The longer answer is that Product.find_by_id(x) calls a generated find_by_ attribute method for the id field, which is the same as calling Product.find(:first, :conditions => ["id = ?", x]). If you look at the documentation for .find, you will notice that it says
Find first - This will return [blah blah black...] If no record can be matched, nil is returned.
Have you given proper relationship in your product model and item model, i think giving proper association can solve your error.

Resources