Dipet
Dipet

Reputation: 323

Understanding hashes

An exercise says:

Create three hashes called person1, person2, and person3, with first and last names under the keys :first and :last. Then create a params hash so that params[:father] is person1, params[:mother] is person2, and params[:child] is person3. Verify that, for example, params[:father][:first] has the right value.

I did

person1 = {first: "Thom", last: "Bekker"}
person2 = {first: "Kathy", last: "Bekker"}
person2 = {first: "Anessa", last: "Bekker"}

then the params hash in Rails

params = {}
params[:father] = person1
params[:mother] = person2
params[:child] = person3

Now I can ask for father, mother or child's first or last name like so params[:father][:first] gives me "Thom".

What makes params[:father][:first][:last] return an error? Is there a way to make that return "Thom Bekker"?

I have no way to check if the way I came up with is correct, is there a better way to do the exercise?

Is there a reason why symbol: is better than symbol =>?

Upvotes: 0

Views: 154

Answers (3)

Jake Shorty
Jake Shorty

Reputation: 727

In Ruby, using square brackets on the Hash or other classes is actually using a method available for an object of that class (this one). When you call these methods in your example, each of these methods will be called and will return its result before the next method is called. So, as you've defined it:

  1. Calling [:father] on params returns the hash represented by person1
  2. [:first] is then called on {first: "Thom", last: "Bekker"}, returning the corresponding value in the hash, "Thom"
  3. [:last] is called on "Thom", which results in an error. Calling square brackets on a string with an integer between them can access the character in a string at that index (person1[:first][0] returns "T"), but "Thom" doesn't have a way of handling the :last symbol inside the square brackets.

There are a number of ways you could get the names printed as you wanted, one of the simplest being combining the string values in person1:

params[:father][:first] + " " + params[:father][:last] returns "Thom Bekker"

Upvotes: 2

Chuck Vose
Chuck Vose

Reputation: 4580

So here's my question, what exactly makes params[:father][:first][:last] return an error? Is there a way to make that return "Thom Bekker"?

Both of these would work

  1. params[:father][:first] + params[:father][:last]
  2. params[:father].values.join(' ')

But maybe it would be better to think about them like the nested structures that they are:

father = params[:father]
name   = father[:first] + father[:last]
puts name

To answer your last question, pretend that there's no difference between a hashrocket => and symbol:. This is one where you don't need to care for a long time. Maybe around year 2 start asking this again, but for learning treat them as if they were equivalent.

(Full disclosure, there are differences, but this is a holy war that you really don't want to see played out)

Upvotes: 0

Todd A. Jacobs
Todd A. Jacobs

Reputation: 84333

Your Return Value is a Single Hash Object

You're misunderstanding the type of object you're getting back. params[:father] returns a single Hash object, not an Array or an Array of hashes. For example:

params[:father]
#=> {:first=>"Thom", :last=>"Bekker"}

params[:father].class
#=> Hash

So, you can't access the missing third element (e.g. :last) because there's no such element within the value of params[:father][:first].

Instead, you could deconstruct the Hash:

first, last = params[:father].values
#=> ["Thom", "Bekker"]

or do something more esoteric like:

p params[:father].values.join " "
#=> "Thom Bekker"

The point is that you have to access the values of the Hash, or convert it to an Array first, rather than treating it directly like an Array and trying to index into multiple values at once.

Upvotes: 2

Related Questions