ruby parse JSON string to hash (JSON.parse, symbolize_names)
- tool
- Ruby
- versions
- Ruby 1.9+ (json in stdlib), Ruby 3.4
- os
- any
JSON.parse(json_string) turns a JSON string into Ruby objects: objects become Hashes with String keys, arrays become Arrays, and true, false, null become true, false, nil. Add symbolize_names: true to get Symbol keys. Load the library with require "json" first; invalid input raises JSON::ParserError.
Parse, access, generate
The example runs CRuby 3.4 compiled to WebAssembly (ruby.wasm, the official Ruby project build) with Node.js:
npm init -y >/dev/null
npm install --silent --no-audit --no-fund @ruby/3.4-wasm-wasi@2.8.1 @ruby/wasm-wasi@2.8.1 >/dev/null 2>&1
cat > ruby.mjs <<'EOF'
import fs from "node:fs/promises";
import { DefaultRubyVM } from "@ruby/wasm-wasi/dist/node";
const wasm = await WebAssembly.compile(await fs.readFile("node_modules/@ruby/3.4-wasm-wasi/dist/ruby+stdlib.wasm"));
const { vm } = await DefaultRubyVM(wasm);
vm.eval(await fs.readFile(process.argv[2], "utf8") + "\n$stdout.flush");
EOF
cat > json.rb <<'EOF'
require "json"
text = '{"name": "errcodex", "pages": 3, "tags": ["ruby", "json"], "draft": false, "owner": null}'
data = JSON.parse(text)
p data
p data["name"], data[:name]
sym = JSON.parse(text, symbolize_names: true)
p sym[:tags].first
puts JSON.generate({ ok: true, n: 1 })
puts JSON.pretty_generate(sym.slice(:name, :pages))
begin
JSON.parse("{'name': 'single quotes'}")
rescue JSON::ParserError => e
puts "#{e.class}: #{e.message.lines.first.strip}"
end
EOF
node --no-warnings ruby.mjs json.rbOutput
{"name" => "errcodex", "pages" => 3, "tags" => ["ruby", "json"], "draft" => false, "owner" => nil}
"errcodex"
nil
"ruby"
{"ok":true,"n":1}
{
"name": "errcodex",
"pages": 3
}
JSON::ParserError: unexpected token at '{'name': 'single quotes'}'data[:name] is nil because the keys are Strings; the symbolize_names version is accessed with Symbols. Single-quoted keys are JavaScript syntax, not JSON, and raise JSON::ParserError.
Options and related methods
| Code | What it does |
|---|---|
| JSON.parse(str) | Parse to Hash/Array with String keys |
| JSON.parse(str, symbolize_names: true) | Use Symbol keys |
| JSON.parse(str, object_class: OpenStruct) | Build another class for JSON objects (require "ostruct" first) |
| JSON.load_file(path) | Read and parse a file |
| JSON.generate(obj) / obj.to_json | Convert Ruby objects to a compact JSON string |
| JSON.pretty_generate(obj) | JSON with line breaks and two-space indentation |
| JSON.parse(str, max_nesting: 10) | Limit nesting depth (default 100) |
Pitfalls
- Missing require. Without
require "json",JSONis unknown and Ruby raises uninitialized constant JSON (Rails and many gems load it for you, plain scripts do not). - String vs Symbol keys. Mixing
data["x"]anddata[:x]is the most common bug; pick one withsymbolize_namesand stick to it. See Symbol vs String. - Empty input.
JSON.parse("")raisesJSON::ParserErrortoo; check for blank strings from HTTP responses or files before parsing. - Large integers and floats are parsed as
Integer(arbitrary size) andFloat; usedecimal_class: BigDecimalwhen exact decimals matter (money). - Numbers as strings. JSON
"42"stays a String; convert explicitly withInteger()(see string to integer).
Confirm it worked
p data.class prints Hash (or Array for a top-level array), and p data.keys shows the keys and whether they are Strings or Symbols.
FAQ
Why is data[:name] nil after JSON.parse?
JSON.parse returns hashes with String keys, so the value is at data["name"]. Pass symbolize_names: true to get Symbol keys and use data[:name].
How do I read and parse a JSON file?
JSON.parse(File.read("config.json")) or JSON.load_file("config.json") (json 2.3+). Both raise JSON::ParserError for invalid content and Errno::ENOENT when the file is missing.
Is JSON.load safe for untrusted input?
Use JSON.parse for untrusted input. JSON.load accepts more options designed for trusted data, and the documentation recommends JSON.parse for data from outside.