If you're coming from JS and learning Ruby like I am, you've probably tried to use Ruby hashes and gotten a fair share of errors.
irb(main):001:0> person = { name: "Jennifer", state: "California" }
irb(main):002:0> person.name
Traceback (most recent call last):
4: from /Users/j/.rbenv/versions/2.6.5/bin/irb:23:in `<main>'
3: from /Users/j/.rbenv/versions/2.6.5/bin/irb:23:in `load'
2: from /Users/j/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/irb-1.2.0/exe/irb:11:in `<top (required)>'
1: from (irb):2
NoMethodError (undefined method `name' for {:name=>"Jennifer", :state=>"California"}:Hash)
irb(main):003:0> person['name']
=> nil
What gives? Ruby was totally fine with how I created the hash - it's exactly how I create JS objects. But I get errors when I try to access it using either:
- the dot notation
person.name
: I get aNoMethodError
- using the bracket notation
person['name']
: I getnil
Let's break down what's happening.
By creating a hash like so:
person = { name: "Jennifer", state: "California" }
I'm using Ruby's new notation for creating a hash. This was introduced in version 1.9 (current version is 2.6).
The old equivalent syntax makes it way easier to understand what's actually happening:
person = { :name => "Jennifer", :state => "California" }
While JS only allows you to use strings as keys1, you can use any object as a key for Ruby hashes. What I'm actually creating is a ruby hash containing 2 key/value pairs:
-
:name
: Ruby symbol pointing to"Jennifer"
(a string) -
:state
: Ruby symbol pointing to"California"
(also a string)
When you use the dot notation person.name
, Ruby interprets that as you trying to call a method called name
on person
. person
doesn't have a name
method, since hashes don't have a name
method. Ruby throws a NoMethodError
as a result.
When you use the bracket notation person['name']
, Ruby tries to retrieve the value associated with a string key 'name'
, not a symbol key :name
. It doesn't find that string key, so it returns nil
.
The right way is to pass in the symbol :name
using the square bracket notation:
irb(main):004:0> person[:name]
=> "Jennifer"
Hope this helps! Anything else you find confusing in Ruby? Comment below
Top comments (0)