loading...

Ruby Hashes vs JS Objects

jmhwang7 profile image Jennifer Hwang ・2 min read

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 a NoMethodError
  • using the bracket notation person['name']: I get nil

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


  1. This is not strictly true anymore. You can use Symbols as JS object keys as of ES6. I still don't see this much though. 

Posted on by:

jmhwang7 profile

Jennifer Hwang

@jmhwang7

Software engineer at Stripe. Working on reducing our AWS bill! I'm a generalist - currently learning more about Ruby.

Discussion

markdown guide