Topic: [SOLVED] Using hashes as parameters

Hello everyone, I have some doubts on something (very simple I know, but google didn't give me any fast answers), and I was hoping you could help me. This is basically what I want to do:

1 - Get a Product using an id.
2 - Pass the products description and price to another method using a hash
3 - Test if the hash contains something
4 - Use the description and the price in the hash to create an Item

def method1()
    product = Product.find(1)
    method2(:description => product.description, :price => product.price)

def method2(*args)

    #Test if args have something
    if ???
       item =
       item.description = args[:description]
       item.price = args[:price]

This is not working however. How do I test the args in the if? How do I get description and price out of the hash?

Thanks a lot for the help.

Last edited by Highter (2010-03-04 16:45:28)

Re: [SOLVED] Using hashes as parameters

def method2(*args)

This is the syntax you use if you want to accept any number of regular parameters. Use this instead for a hash:

def method2(attributes)

You can then use regular hash methods, for example:

unless attributes[:description].blank?
Rob Anderton

Re: [SOLVED] Using hashes as parameters

Rob, thanks for the help, it worked. Just two more things:

1 - I tried calling method2() and got an error. I changed the method definition to method2(attributes=nil) and it worked. Is this how it's done? I was using *args because I thought that the * would allow me to make the method call without using any parameter.

2 - What's this *args I keep seeing in the rails API? What's it supposed to do?

Re: [SOLVED] Using hashes as parameters

The reason your code works as attributes = nil, is because if you dont pass anything in, it will set attributes to nil. You code isnt referencing attributes anywhere so it doesnt do anything. When you use *args, its expecting you to pass something into the function when you call it. All the * is doing, it telling it that you might have 1 to many arguments coming in, that you can reference as an array.

Re: [SOLVED] Using hashes as parameters

method2(attributes=nil) is ok, personally i'd use method2(attributes={}) meaning attributes will be set to an empty hash if you call it with no parameters.

Rob Anderton

Re: [SOLVED] Using hashes as parameters

*args is pretty smart - if it gets key-value pairs it will put them into a hash for you, giving you the standard approach to dealing with method parameters, which could be summed up as  "the parameters to a method should be a list of the essential things the method needs to work (and this can be a list of zero length), followed by a hash containing any other optional parameters that will modify the behaviour".

def my_method(essential_param1, essential_param2, options ={})

This is pretty much the standard approach - the method won't work without essential_params 1 and 2.   *args will do this for you automatically though:

def my_method(*args)
  puts "recieved #{args.inspect}"

>> my_method
recieved []
=> nil
>> my_method(1,2,3)
recieved [1, 2, 3]
=> nil
>> my_method(1, :foo => "bar", :chunky => "bacon")
recieved [1, {:chunky=>"bacon", :foo=>"bar"}]
=> nil
>> my_method(1, "hello", :a_symbol, :foo => "bar", :chunky => "bacon")
recieved [1, "hello", :a_symbol, {:chunky=>"bacon", :foo=>"bar"}]

Rails gives you a nice helper to pull options out of this, ie to assign the hash (if it's there) to the variable called 'options':
options = args.extract_options!

Let's rewrite my_method to show this off, continuing on the assumption that the method needs two essential params in the list and then can have an options hash as well.

>> def my_method(*args)
>>   options = args.extract_options!
>>   puts "args[0] = #{args[0].inspect}, args[1] = #{args[1].inspect}"
>>   puts "options = #{options.inspect}"
>> end
=> nil
>> my_method(1, "hello", :a_symbol, :foo => "bar", :chunky => "bacon")
args[0] = 1, args[1] = "hello"
options = {:chunky=>"bacon", :foo=>"bar"}

This pattern is used throughout rails.  eg, look at the source code for AR::Base.find, which is very simple, basically getting some options and then deciding what to do next depending on what the first argument is. … ;name=find

Last edited by Max Williams (2010-03-08 13:29:14)

#If i've helped you then please recommend me at Working With Rails:
# … i-williams