JSON & YAML

Reviewed & published by Brayan K

JSON and YAML are two text formats for serializing data, and Ruby's standard library converts between them and native hashes and arrays with a single method call in each direction.

Part of the free Ruby course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

You'll parse and generate JSON, symbolize keys, and round-trip a hash through YAML.

What You'll Learn in This Lesson

1️⃣ Parsing JSON into Ruby

require 'json', then JSON.parse(string) returns a Hash/Array tree. By default object keys come back as strings; pass symbolize_names: true to get symbol keys, which read more naturally as data[:name].

require 'json'

# Parse a JSON string into Ruby data (hash + array).
text = '{"name": "Ada", "langs": ["ruby", "c"], "active": true}'
data = JSON.parse(text)

puts data.class                 # Hash
puts data["name"]               # keys are STRINGS by default
puts data["langs"].inspect
puts data["active"]

# symbolize_names: true turns keys into symbols instead.
sym = JSON.parse(text, symbolize_names: true)
puts sym[:name]                 # now access with a symbol

2️⃣ Generating JSON from Ruby

JSON.generate(obj) and the shortcut obj.to_json produce a compact string. For human-readable output with indentation, use JSON.pretty_generate. Notice symbol keys come out as plain JSON strings.

require 'json'

person = { name: "Ada", age: 36, langs: ["ruby", "c"] }

# generate / to_json produce a compact JSON string:
puts JSON.generate(person)
puts person.to_json

# pretty_generate adds indentation for humans:
puts JSON.pretty_generate(person)

3️⃣ YAML: Dump, Load & Round-Trip

YAML is the go-to for human-edited config. require 'yaml', then YAML.dump(obj) writes a YAML string (note the leading --- document marker) and YAML.load(string) reads it back — a clean round-trip.

require 'yaml'

config = {
  "app"     => "blog",
  "port"    => 3000,
  "features"=> ["search", "comments"],
  "debug"   => false
}

# dump: Ruby -> YAML text
yaml = YAML.dump(config)
puts yaml

# load: YAML text -> Ruby (round-trip)
back = YAML.load(yaml)
puts "round-trips equal? #{back == config}"
puts back["features"].inspect

Your turn. Parse a small JSON object using symbol keys and read two values. Fill in each ___.

require 'json'

# 🎯 YOUR TURN — replace each ___ then run with: ruby place.rb
text = '{"city": "Paris", "visited": false}'

# Parse with SYMBOL keys so we can use [:city] not ["city"]:
data = JSON.parse(text, ___: true)   # 👉 the option that symbolizes keys

puts data[:city]
puts data[:___]                      # 👉 read the "visited" value

# ✅ Expected output:
#    Paris
#    false

Mini-Challenge: Process a Users Feed

Parse a JSON array of users, filter the admins, and emit a JSON summary. This parse → transform → generate flow is the heart of working with APIs. Run with ruby users.rb.

# 🎯 MINI-CHALLENGE: process a users feed.
# Save as users.rb and run with: ruby users.rb
#
# 1. require 'json'.
# 2. Parse a JSON array of user objects with symbolize_names: true.
# 3. Select the admins and collect their names.
# 4. Build a summary hash { total:, admin_count: } and print it as JSON.
#
# ✅ Example output:
#    Admins: Ada, Cy
#    {"total":3,"admin_count":2}

# your code here

Common Errors (and the fix)

Pro Tips

📋 Quick Reference — JSON & YAML

TaskRuby
Parse JSONJSON.parse(str)
Symbol keyssymbolize_names: true
To JSONobj.to_json
Pretty JSONJSON.pretty_generate(obj)
Dump YAMLYAML.dump(obj)
Load YAMLYAML.load(str)

🎉 Lesson Complete!

Practice quiz

What must you require before using JSON methods?

  • require 'parser'
  • import json
  • require 'json'
  • include JSON

Answer: require 'json'. require 'json' loads the standard-library JSON module.

What does JSON.parse return for a JSON object?

  • a Hash
  • a String
  • an Array
  • a Struct

Answer: a Hash. A JSON object parses into a Ruby Hash (arrays become Arrays).

By default, JSON.parse gives object keys as:

  • symbols
  • integers
  • nil
  • strings

Answer: strings. Keys come back as strings unless you request symbols.

Which option makes JSON.parse return symbol keys?

  • symbols: true
  • symbolize_names: true
  • as_symbols: true
  • keys: :symbol

Answer: symbolize_names: true. Pass symbolize_names: true to get symbol keys like data[:name].

Which produces a compact JSON string from a Ruby object?

  • obj.to_json
  • obj.to_s
  • obj.dump
  • obj.inspect

Answer: obj.to_json. to_json (or JSON.generate) produces a compact JSON string.

Which method produces indented, human-readable JSON?

  • JSON.generate
  • JSON.format
  • JSON.pretty_generate
  • JSON.indent

Answer: JSON.pretty_generate. JSON.pretty_generate adds indentation for readability.

What happens to Ruby symbols when converted to JSON?

  • they stay symbols
  • they become strings
  • they raise an error
  • they become nil

Answer: they become strings. JSON has no symbol type, so symbols become strings.

Which method serializes a Ruby object to YAML text?

  • YAML.parse
  • YAML.write
  • YAML.to_yaml
  • YAML.dump

Answer: YAML.dump. YAML.dump converts a Ruby object into a YAML string.

What marker begins a YAML document produced by YAML.dump?

  • ===
  • ---
  • %YAML
  • #yaml

Answer: ---. YAML documents begin with the --- document marker.

For untrusted YAML input you should prefer:

  • YAML.load with no limits
  • eval
  • YAML.safe_load
  • JSON.parse

Answer: YAML.safe_load. safe_load only allows basic types, avoiding object-injection risks.

Continue this course

Frequently asked questions

What's the difference between JSON.parse and JSON.generate?

JSON.parse takes a JSON string and returns Ruby objects — a JSON object becomes a Hash, an array becomes an Array, true/false/null become true/false/nil. JSON.generate (and the convenient obj.to_json) goes the other direction, turning Ruby data into a compact JSON string. Together they let you read data from APIs or files and write it back out in a portable format.

Why are my JSON keys strings instead of symbols?

JSON has no concept of symbols, so JSON.parse defaults to string keys, meaning you access values with data["name"]. Pass symbolize_names: true to get symbol keys (data[:name]) instead, which is often nicer in Ruby code. Be cautious symbolizing keys from untrusted input on very old Ruby versions, but on modern Ruby symbols are garbage-collected so it's safe.

When should I use YAML instead of JSON?

JSON is the lingua franca for web APIs and data interchange — compact and supported everywhere. YAML is more human-friendly with its indentation and lack of braces, which is why it dominates configuration files (think .yml CI configs and Rails settings). Use JSON for machine-to-machine data and YAML for files humans edit by hand. Ruby's YAML.load even parses JSON, since JSON is a subset of YAML.

Is it safe to load arbitrary YAML?

Be careful. The full YAML loader can instantiate Ruby objects, which is a security risk with untrusted input. Modern Ruby's YAML.load is safe by default (it only allows basic types), and YAML.safe_load lets you whitelist permitted classes explicitly. For data you don't control, prefer safe_load and never use the unsafe loader. For your own trusted config files, plain load/dump is fine.