I\'m playing with Ruby on Rails and I\'m trying to create a method with optional parameters. Apparently there are many ways to do it. I trying naming the optional parameters
To answer the question of "why?": the way you're calling your function,
my_info "Bill", age: 99, weight: 300, city: "Sao Paulo"
is actually doing
my_info "Bill", {:age => 99, :weight => 300, :city => "Sao Paulo"}
Notice you are passing two parameters, "Bill"
and a hash object, which will cause the default hash value you've provided in my_info2
to be completely ignored.
You should use the default value approach that the other answerers have mentioned.
You can also define method signatures with keyword arguments (New since, Ruby 2.0, since this question is old):
def my_info2(name, age: 27, weight: 160, city: "New York", **rest_of_options)
p [name, age, weight, city, rest_of_options]
end
my_info2('Joe Lightweight', weight: 120, age: 24, favorite_food: 'crackers')
This allows for the following:
:weight
and :age
):favorite_food
collected in rest_of_options
)If you want to default the values in your options hash, you want to merge the defaults in your function. If you put the defaults in the default parameter itself, it'll be over-written:
def my_info(name, options = {})
options.reverse_merge!(age: 27, weight: 160, city: "New York")
...
end
#fetch
is your friend!
class Example
attr_reader :age
def my_info(name, options = {})
@age = options.fetch(:age, 27)
self
end
end
person = Example.new.my_info("Fred")
puts person.age #27
I don't see anything wrong with using an or operator to set defaults. Here's a real life example (note, uses rails' image_tag
method):
file:
def gravatar_for(user, options = {} )
height = options[:height] || 90
width = options[:width] || 90
alt = options[:alt] || user.name + "'s gravatar"
gravatar_address = 'http://1.gravatar.com/avatar/'
clean_email = user.email.strip.downcase
hash = Digest::MD5.hexdigest(clean_email)
image_tag gravatar_address + hash, height: height, width: width, alt: alt
end
console:
2.0.0-p247 :049 > gravatar_for(user)
=> "<img alt=\"jim's gravatar\" height=\"90\" src=\"http://1.gravatar.com/avatar/<hash>\" width=\"90\" />"
2.0.0-p247 :049 > gravatar_for(user, height: 123456, width: 654321)
=> "<img alt=\"jim's gravatar\" height=\"123456\" src=\"http://1.gravatar.com/avatar/<hash>\" width=\"654321\" />"
2.0.0-p247 :049 > gravatar_for(user, height: 123456, width: 654321, alt: %[dogs, cats, mice])
=> "<img alt=\"dogs cats mice\" height=\"123456\" src=\"http://1.gravatar.com/avatar/<hash>\" width=\"654321\" />"
It feels similar to using the initialize method when calling a class.