Reputation: 4203
At a point in my code, I expect current_part
to sometimes be nil
, and I want to run some code (inside an if
block) when that's not the case.
Using script/server --debugger
, I've established that current_part
is in fact nil
at that point when the following errors occur.
All the following versions generate the can't convert nil into String
error on the second line:
def map_concepts_to_part(part, current_part)
if current_part
part.concepts.map { |concept| content_tag(:li, "stuff...")}.join
end
end
def map_concepts_to_part(part, current_part)
if test_if_exists(current_part)
part.concepts.map { |concept| content_tag(:li, "stuff...")}.join
end
end
def test_if_exists(test_subject)
test_subject rescue nil
end
def map_concepts_to_part(part, current_part)
if test_if_complete(current_part)
part.concepts.map { |concept| content_tag(:li, "stuff...")}.join
end
end
def test_if_complete(test_subject)
test_subject.id rescue nil
end
def test_if_complete(part, current_part)
unless current_part.to_s == ""
part.concepts.map { |concept| content_tag(:li, "stuff...")}.join
end
end
def test_if_complete(part, current_part)
unless current_part.nil?
part.concepts.map { |concept| content_tag(:li, "stuff...")}.join
end
end
PS, the truncated line in each of the above is:
part.concepts.map { |concept| content_tag(:li, "Concept: “" + concept.title + "”", :class => "one_concept") + content_tag(:li, "Attached images (" + concept.images.size.to_s + ")", :class => "all_images") + content_tag(:li, "Attached docs (XX)", :class => "all_docs")}.join
Upvotes: 2
Views: 15459
Reputation: 7856
The problem is in your truncated line where concept.title meets the plus.
When you do
"Foo" + some_obj.some_attr
and some_attr in the object is nil, Ruby won't autocast it to string. Might happen often (!) since Rails casts NULL value in the DB to nils. Workarounds are in-string evaluation:
"Foo #{some_obj.attr_that_can_be_nil}"
pattern substitution (automatically truncates nil)
"Foo %s" % some_obj.attr_that_can_be_nil
or array joining (idem ditto)
["Foo ", some_obj.attr_that_can_be_nil].join
The reason you could not find it is that your "truncated line" deserves it's own 5-6 lines unwrapped properly, that way it would be much easier for you to spot the problem.
On a sidenote, you don't need “ and friends - just type it literally since Rails is UTF-8 nowadays anyway. Moreover, when passing stuff to tag helpers you might get this thing converted to “ which is totally not what you want (if helpers escape entities - I don't remember if they do, but Builder certainly does).
Upvotes: 3
Reputation: 23990
Is that a local variable in some partial? if so, then even doing current_part.nil?
will raise an error in case that variable is not passed to the partial.
to overcome this do:
counter_part = defined?(counter_part) ? : counter_part : nil
BTW: Normally, Ruby looks for an assignment statement to determine whether something is a
variable—if a name hasn’t been assigned to, then Ruby assumes that name is a method call, so executing the following statement will raise an error if x
wasn't initialized:
irb(main):001:0> puts "yes nil" if x.nil?
#=>NameError: undefined local variable or method `x' for main:Object
Upvotes: 0
Reputation: 26271
The test current_part.to_s == ""
returns true
on my ruby system when current_part
is nil
. Unlike some other languages, you can say nil.to_s
and nil.nil?
and have them work. I think there is something else that is causing the problem. Can you show more of the code?
(My tests were in ruby 1.8.6)
Edit: Looking around, what usually causes the above error is an expression such as "text" + nil
, not nil.to_s
. Do you have anything like that around?
Upvotes: 5
Reputation: 803
If the object is nil, then you can't use any of its member because the object itself does not exist. So the comparison should be of the object and nil, not a member of the object and nil.
It's like a null pointer exception.
You should use something like
x = get_some_object if x.nil?
to initialize the variable x if uninitialized.
Upvotes: 0
Reputation: 1151
Tobias is right. You cannot access any member of the object if it is nil (as it does not exist). You must check for nil value before performing any operation or before accessing any member varible or function.
In cpp, is it like:
if(!current_part) { perform operation }
` This is a very common NPE(Null Pointer Exception) in almost every programming language.
Upvotes: 0