Question

How to Parse a JSON String in Ruby

rubyjson

Question

I have a JSON-formatted string in Ruby:

string = '{"desc":{"someKey":"someValue","anotherKey":"value"},"main_item":{"stats":{"a":8,"b":12,"c":10}}}'

What is the simplest way to parse this string and extract values from it, including nested data?

Short Answer

By the end of this page, you will understand how to parse a JSON string in Ruby using the built-in JSON library, how to access nested hash values, and how to avoid common errors when working with parsed JSON data.

Concept

JSON is a text format used to represent structured data. In Ruby, when you parse a JSON string, Ruby converts that text into normal Ruby objects such as Hash, Array, String, Integer, Float, true, false, and nil.

For JSON objects like this:

{"name":"Alice","age":30}

Ruby usually converts them into a Hash:

{"name" => "Alice", "age" => 30}

This matters because many real programs receive data as JSON:

  • API responses
  • Configuration files
  • Webhook payloads
  • Data exchanged between services
  • Frontend-to-backend communication

If you can parse JSON, you can turn raw text into data your Ruby code can actually use.

In your example, the JSON contains nested objects. After parsing, you can access them with chained hash lookups.

Ruby does not automatically treat a JSON string as a hash. You must first parse it with the json library.

Mental Model

Think of a JSON string as a sealed cardboard box with labels written on the outside. You can see it is structured, but you cannot directly grab the contents.

Parsing is the act of opening the box and organizing everything onto shelves.

  • The JSON string is the sealed box
  • JSON.parse opens the box
  • Ruby hashes and arrays are the organized shelves
  • Keys like "desc" or "stats" are labels you use to find items

Before parsing, it is just text. After parsing, it becomes usable Ruby data.

Take Quiz

Syntax and Examples

The usual way to parse JSON in Ruby is:

require 'json'

data = JSON.parse(json_string)

Basic example

require 'json'

string = '{"desc":{"someKey":"someValue","anotherKey":"value"},"main_item":{"stats":{"a":8,"b":12,"c":10}}}'

data = JSON.parse(string)

puts data["desc"]["someKey"]     # someValue
puts data["desc"]["anotherKey"]  # value
puts data["main_item"]["stats"]["a"] # 8
puts data["main_item"]["stats"]["b"] # 12
puts data["main_item"]["stats"]["c"] # 10

What the parsed result looks like

{
  "desc" => {
    "someKey" => "someValue",
    "anotherKey" => "value"
  },
  "main_item" => {
    "stats" => {
      "a" => 8,
      "b" => 12,
      "c" => 10
    }
  }
}

Using symbol keys

By default, JSON.parse creates string keys. If you want symbols instead:

require 'json'

string = '{"desc":{"someKey":"someValue"}}'

data = JSON.parse(string, symbolize_names: true)

puts data[:desc][:someKey]

Use this only when you intentionally want symbol keys, and be consistent throughout your code.

Step by Step Execution

Consider this example:

require 'json'

string = '{"main_item":{"stats":{"a":8}}}'
data = JSON.parse(string)
value = data["main_item"]["stats"]["a"]
puts value

Step by step

  1. Ruby loads the JSON library with:
require 'json'
  1. The variable string contains plain text:
'{"main_item":{"stats":{"a":8}}}'

At this point, Ruby sees it as a String, not a Hash.

  1. JSON.parse(string) reads the JSON text and converts it into nested Ruby hashes:
{
  "main_item" => {
    "stats" => {
      "a" => 8
    }
  }
}
  1. data["main_item"] returns:
{ "stats" => { "a" => 8 } }
  1. data["main_item"]["stats"] returns:
{ "a" => 8 }
  1. data["main_item"]["stats"]["a"] returns:
8
  1. puts value prints:
8

Real World Use Cases

Parsing JSON in Ruby is common in many practical situations:

  • Calling APIs: A Ruby app fetches weather, payment, or user data from an external service.
  • Rails controllers: Incoming request bodies may be JSON.
  • Background jobs: Workers process JSON payloads from queues.
  • Configuration: Some tools store settings in JSON files.
  • Logging and analytics: Events may be stored or transmitted as JSON.
  • Web scraping or integrations: External systems often return JSON instead of XML.

Example: parsing an API response

require 'json'

response_body = '{"user":{"name":"Ava","active":true}}'
user_data = JSON.parse(response_body)

puts user_data["user"]["name"]   # Ava
puts user_data["user"]["active"] # true
Take Quiz

Real Codebase Usage

In real projects, developers rarely stop at just JSON.parse. They usually combine parsing with validation and safe access.

1. Parse once, then reuse

data = JSON.parse(response.body)
user_name = data["user"]["name"]

Avoid parsing the same JSON string repeatedly.

2. Guard against missing keys

if data["main_item"] && data["main_item"]["stats"]
  puts data["main_item"]["stats"]["a"]
end

Or with dig:

puts data.dig("main_item", "stats", "a")

3. Handle invalid JSON

require 'json'

begin
  data = JSON.parse(string)
rescue JSON::ParserError => e
  puts "Invalid JSON: #{e.message}"
end

4. Normalize key style

Teams often choose either:

  • string keys: data["name"]
  • symbol keys: data[:name]

Mixing both causes bugs.

5. Extract values into clearer variables

stats = data.dig("main_item", "stats")
a_value = stats["a"] if stats

This makes code easier to read and test.

Common Mistakes

1. Forgetting to require the JSON library

Broken code:

data = JSON.parse(string)

Fix:

require 'json'
data = JSON.parse(string)

2. Using symbol keys when the parsed hash has string keys

Broken code:

require 'json'

data = JSON.parse('{"name":"Ruby"}')
puts data[:name]

This returns nil because the key is "name", not :name.

Fix:

puts data["name"]

Or parse with symbols:

data = JSON.parse('{"name":"Ruby"}', symbolize_names: true)
puts data[:name]

3. Trying to access nested keys without checking structure

Broken code:

puts data["main_item"]["stats"]["z"]

This may return nil, and further chaining can crash.

Safer approach:

puts data.dig("main_item", "stats", "z")

4. Invalid JSON formatting

JSON requires double quotes around keys and string values.

Broken code:

string = "{desc: {someKey: 'someValue'}}"

Fix:

string = '{"desc":{"someKey":"someValue"}}'

5. Confusing JSON with Ruby hash syntax

Ruby hash syntax:

{ desc: { someKey: "someValue" } }

JSON syntax:

'{"desc":{"someKey":"someValue"}}'

They look similar, but they are not the same thing.

Comparisons

ConceptWhat it isExampleWhen to use
JSON stringRaw text in JSON format'{"a":1}'When data arrives from APIs, files, or requests
Parsed Ruby hashRuby data structure created from JSON{ "a" => 1 }When you want to access and use the data
String keysDefault result from JSON.parsedata["a"]Best when matching JSON exactly
Symbol keysOptional parsing modedata[:a]Useful if your codebase prefers symbols

[] vs dig

MethodExampleResultBest for
[]data["main_item"]["stats"]["a"]Direct accessWhen you know the structure exists
digdata.dig("main_item", "stats", "a")Safe nested lookupWhen keys may be missing

JSON vs Ruby hash literal

FeatureJSONRuby Hash
KeysMust be in double quotesCan be strings or symbols
String valuesMust use double quotesCan use normal Ruby string syntax
PurposeData interchange formatNative Ruby object
Example{"a":1}{ "a" => 1 } or { a: 1 }
Take Quiz

Cheat Sheet

require 'json'

Parse JSON

data = JSON.parse(json_string)

Access nested values

data["desc"]["someKey"]
data["main_item"]["stats"]["a"]

Safe nested access

data.dig("main_item", "stats", "a")

Parse with symbol keys

data = JSON.parse(json_string, symbolize_names: true)
data[:main_item][:stats][:a]

Handle invalid JSON

begin
  data = JSON.parse(json_string)
rescue JSON::ParserError => e
  puts e.message
end

Rules to remember

  • JSON text must be parsed before use.
  • JSON.parse returns string keys by default.
  • JSON uses double quotes for keys and strings.
  • Use dig for safer nested lookups.
  • Do not mix string keys and symbol keys unless you mean to.

Your example

require 'json'

string = '{"desc":{"someKey":"someValue","anotherKey":"value"},"main_item":{"stats":{"a":8,"b":12,"c":10}}}'
data = JSON.parse(string)

data["desc"]["someKey"]          # => "someValue"
data["main_item"]["stats"]["b"] # => 12

FAQ

How do I parse a JSON string in Ruby?

Use the json library and call JSON.parse:

require 'json'
data = JSON.parse(string)

Why does data[:key] return nil after parsing JSON?

Because JSON.parse uses string keys by default. Use data["key"] or parse with symbolize_names: true.

How do I access nested JSON values in Ruby?

Use chained hash lookups:

data["main_item"]["stats"]["a"]

Or use dig for safer access:

data.dig("main_item", "stats", "a")

What happens if the JSON string is invalid?

Ruby raises JSON::ParserError. You should rescue it if the input may be malformed.

Is JSON the same as a Ruby hash?

No. JSON is a text format. A Ruby hash is a native Ruby object. JSON.parse converts JSON text into Ruby objects.

Can Ruby parse arrays from JSON too?

Yes. JSON arrays become Ruby arrays.

JSON.parse('[1, 2, 3]')
# => [1, 2, 3]

Do I always need require 'json'?

In normal Ruby scripts, yes. Some frameworks may load it for you, but it is best not to assume that.

Take Quiz

Mini Project

Description

Build a small Ruby script that parses a JSON string representing product information and prints selected values. This demonstrates the core skills you need when receiving structured data from an API or file.

Goal

Parse nested JSON in Ruby and safely extract values from the result.

Requirements

  1. Store a JSON string in a Ruby variable.
  2. Parse the string using Ruby's JSON library.
  3. Print at least three nested values from the parsed data.
  4. Use dig for at least one safe lookup.
  5. Handle invalid JSON with basic error handling.
Take Quiz

Keep learning

Related questions

View more