Tired of using defined? all the time


#1

Hi everyone,

It seems like every time I want to evaluate a possibly undefined
variable I
have to use defined? to see that it exists first, so I can’t simply have

– if params[:range_start] > 3

or something like it. I need to have

– if defined? params[:range_start] && params[:range_start] > 3

I can’t even have

– if params[:range_start].nil?

This is really annoying - is there anyway to avoid this?

Thanks,
Daniel H.


#2

On 4/15/06, Daniel H. removed_email_address@domain.invalid wrote:

I can’t even have

– if params[:range_start].nil?

This is really annoying - is there anyway to avoid this?

You can do things like this:
a = 1/0 rescue 5

Which is particularly handy when you’re calling a method on something
that might be nil, and you can’t easily deal with it in another way.

However, given the particular example you used… are you sure you’re
having the problem you think you have?
In a Rails controller action, you’re always going to have ‘params’…
so you only need to deal with the issue of a particular missing
parameter.

if params[:range_start] || 0 > 3
stuff
end

Since the default value of the hash is nil, that will evaluate to "if 0

3"


#3

On Apr 15, 2006, at 08:22 PM, Daniel H. wrote:

It seems like every time I want to evaluate a possibly undefined
variable I
have to use defined? to see that it exists first, so I can’t simply
have

I can honestly say that I’ve never actually made a call to defined?,
in all the Ruby code I’ve written in the last 10+ months…

– if params[:range_start] > 3

This can be: if params[:range_start].to_i > 3. Using the to_i method
will return zero if :range_start isn’t in the params hash.

or something like it. I need to have

– if defined? params[:range_start] && params[:range_start] > 3

If you want to go this way, you could simply say:

if params[:range_start] && params[:range_start] > 3, but that’s
far more verbose than you need to be.

I can’t even have

– if params[:range_start].nil?

This works for me, on every Hash object I’ve ever tried it on. Are
you getting an exception when you do this?

This is really annoying - is there anyway to avoid this?

I’m thinking you’re doing something that’s not quite right. The
behavior you’re describing goes against everything I’ve seen, with
regard to how Ruby Hash objects work.

-Brian


#4

On Apr 15, 2006, at 09:25 PM, Daniel H. wrote:

(params[:search][:destination_city_id] || 0 < 1)
OK. That error is actually telling you that params[:search] is nil.
You can’t access a nil object as though it were a Hash or Array, so
if params[:search] is nil, you would be saying nil[:starting_city].
Make sure you look at the debug output of the params object, which is
also present on that page. You’ll likely see that there’s no sub-hash
with a key of “search”.

Also, I would actually recommend doing my to_i transformation on the
object you want from params. Not only will this remove the need for
using “x || 0 < 1”, it’s a good idea to make sure you are working
with integers on both sides of the comparison. All scalar values in
the params hash are strings when they get to your controller. This is
a quirk of the way HTML post data is encoded and sent in the HTTP
request…

-Brian


#5

I apologize if this is a very newbified response, but when I try
something
like the example you gave, I get:

You have a nil object when you didn’t expect it!
You might have expected an instance of Array.
The error occured while evaluating nil.[]

The code in my controller is:
unless (params[:search][:starting_city_id] || 0 < 1) ||
(params[:search][:destination_city_id] || 0 < 1)


#6

Right, there isn’t a sub-hash with key of “search”. Is there anyway to
evaluate

params[:search][:starting_city_id].to_i < 1

without using defined? and without getting an error in the instances
when
params[:search] is nil?

In this particular case it’s not absolutely necessary to group
:starting_city_id and :destination_city_id in the :search hash , I just
like
to keep related variables together like that. Am I just coding
ineffectively?


#7

Testing for definition is the “correct” thing to do because you’ve
already
forseen that it could be undefined. However… you might try using an
exception:

params[:search][:starting_city_id].to_i < 1 rescue nil

If your params[:search] is undefined, you will get a NameError exception
and
the expression will evaluate to nil.

Just a thought

View this message in context:
http://www.nabble.com/tired-of-using-defined-all-the-time-t1456604.html#a3937098
Sent from the RubyOnRails Users forum at Nabble.com.


#8

On 4/16/06, Brian V Hughes removed_email_address@domain.invalid wrote:

You have more or less complete control over what appears in your
controller’s params object.

Only for well behaved users who are using the forms you send to their
browser.


#9

You have more or less complete control over what appears in your
controller’s params object. The primary reason you would have params
[:search][:starting_city] is if you have a field in the form of the
page that calls the controller you are in, whose name attribute is
“search[starting_city]”. If you don’t, then you need to either fix
the form being submitted, or fix your controller code to reference
objects that should be in params.

Testing for params[:search} seems to be counter-intuitive, when you
should be looking take control of what data is being submitted to
your controller, before start trying to post-process the submitted
data. If there’s a legitimate reason for params to sometimes not have
a [:search] key, then I recommend wrapping a conditional around that
fact:

if params[:search] … end
unless params[:search].nil? … end

-Brian


#10

Thanks everyone for your input. It looks like it’s just not possible to
have
something like,

some[:multi][:dimensional][:hash].to_s

without checking that each dimension along the way exists, or without
rescuing the operation, unlike in PHP (shudder) where you can have
something
like

if($_POST[‘search’][‘cabarets’]) blah blah blah

Though I guess I COULD do this without worrying about it by extending
Nil to
have [] return a nil object.

Thanks again fellas!


#11

On Apr 16, 2006, at 1:15 AM, Daniel H. wrote:

if($_POST[‘search’][‘cabarets’]) blah blah blah

Though I guess I COULD do this without worrying about it by
extending Nil to
have [] return a nil object.

Please don’t do that! You will run into all kinds of weird problems
if you start defining methods like that on NilClass.

-Ezra


#12

Lol ok! Thanks for your help!


#13

How about a helper?

if_params(:search,:cabarets)
#do stuff here
end

I am no Ruby expert, but I am certain you could set up your helper to
work
for any depth array and check for nils the whole way down. If if_params
is
to long, you could shorten it to ifp or something similar.