Ruby'de JSON ile çalışmak için önce require "json" yazarsınız. Metni Ruby nesnesine çevirmek için JSON.parse, Ruby nesnesini JSON metnine çevirmek için JSON.generate ya da nesnenin to_json metodu kullanılır. Okunabilir, girintili çıktı için JSON.pretty_generate vardır. Anahtarların metin yerine sembol olmasını istiyorsanız JSON.parse(metin, symbolize_names: true) yazarsınız; geçersiz girdide JSON::ParserError fırlatılır.
json kütüphanesi Ruby ile birlikte gelen bir varsayılan gem'dir; Ruby 4.0 NEWS dosyasına göre bu sürümle json 2.18.0 geliyor ve bizim denememizde JSON::VERSION değeri "2.18.0" döndü. Aşağıdaki örnekleri Ruby 4.0.9 ile çalıştırdık. Ruby 4.0'da hash'lerin inspect çıktısının {ad: "Ayşe"} ve {"ad" => "Ayşe"} biçiminde göründüğünü unutmayın. Dilin geneli için Ruby öğrenme rehberi sayfasına bakabilirsiniz.
JSON ve Ruby türlerinin karşılıkları
![JSON ve Ruby türlerinin karşılıkları: nesne {"a": 1}, dizi [1, 2], metin "abc", sayı 1 ve 1.5](/assets/blog/ruby-json-kullanimi-b1.webp)
| JSON değeri | JSON.parse sonucu | JSON.generate girdisi |
|---|---|---|
| nesne {"a": 1} | Hash | Hash |
| dizi [1, 2] | Array | Array |
| metin "abc" | String | String, Symbol metne çevrilir |
| sayı 1 ve 1.5 | Integer ve Float | Integer ve Float |
| true, false | true, false | true, false |
| null | nil | nil |
Bu dört temel türün dışında kalan nesneler, örneğin Time, varsayılan olarak metin temsilleriyle yazılır. Geri okurken yine metin olarak gelirler; JSON tarih türü tanımaz.
JSON.parse ile metni Ruby nesnesine çevirmek
require "json"
kaynak = '{"ad": "Ayşe", "yas": 30, "aktif": true, "etiketler": ["ruby", "json"], "not": null}'
veri = JSON.parse(kaynak)
veri
# => {"ad" => "Ayşe", "yas" => 30, "aktif" => true, "etiketler" => ["ruby", "json"], "not" => nil}
veri["ad"] # => "Ayşe"
veri.class # => Hash
JSON.parse("42") # => 42
JSON.parse('"metin"') # => "metin"
JSON.parse("2.0e2") # => 200.0Kaynak bir JSON nesnesiyse sonuç Hash, diziyse Array olur; tek başına bir sayı ya da metin de geçerli JSON sayılır. Belge, JSON.parse! adında bazı kontrolleri atlayan bir sürüm de olduğunu, bunun yalnızca güvenilir veri için kullanılması gerektiğini belirtiyor.
symbolize_names: anahtarları sembol yapmak
Varsayılan olarak anahtarlar metin olarak gelir. symbolize_names: true verdiğinizde tüm iç içe hash'lerde anahtarlar sembole çevrilir. Böylece veri[:ad] biçiminde erişebilir ya da sonucu doğrudan anahtar kelime argümanlarına aktarabilirsiniz:
s = JSON.parse(kaynak, symbolize_names: true)
s
# => {ad: "Ayşe", yas: 30, aktif: true, etiketler: ["ruby", "json"], not: nil}
s[:etiketler] # => ["ruby", "json"]
JSON.parse('{"a": {"b": [1, 2]}}').dig("a", "b", 1) # => 2Sembol ve metin farkı Ruby Symbol ve String farkı yazısında, dig ve diğer hash metotları Ruby Hash metotları yazısında.
JSON.generate ve to_json ile JSON üretmek

JSON.generate en kısa çıktıyı üretir: tek satır, boşluksuz. require "json" sonrasında temel sınıflara eklenen to_json metodu da aynı sonucu verir. Sembol anahtarlar ve sembol değerler metne çevrilir, nil değeri null olur:
siparis = {no: 1024, urun: "Çay", adet: 3, fiyat: 12.5, teslim: nil, etiket: :acil}
JSON.generate(siparis)
# => "{\"no\":1024,\"urun\":\"Çay\",\"adet\":3,\"fiyat\":12.5,\"teslim\":null,\"etiket\":\"acil\"}"
siparis.to_json == JSON.generate(siparis) # => true
[1, "iki", nil, true].to_json # => "[1,\"iki\",null,true]"
"Merhaba".to_json # => "\"Merhaba\""Türkçe karakterler varsayılan olarak olduğu gibi yazılır. ASCII dışındaki her karakteri kaçışlı yazmak isterseniz ascii_only: true seçeneğini kullanın:
JSON.generate("ğüş", ascii_only: true) # => "\"\\u011f\\u00fc\\u015f\""pretty_generate ile okunabilir çıktı
JSON.pretty_generate, iki boşluk girinti, iki noktadan sonra bir boşluk ve her öğeden sonra yeni satır kullanır. Yapılandırma dosyası yazarken ya da hata ayıklarken işinize yarar:
puts JSON.pretty_generate(siparis)
# çıktı:
# {
# "no": 1024,
# "urun": "Çay",
# "adet": 3,
# "fiyat": 12.5,
# "teslim": null,
# "etiket": "acil"
# }Daha ince ayar için JSON.generate metoduna indent, space, space_before, object_nl ve array_nl seçeneklerini verebilirsiniz.
Kendi sınıfınız için to_json
Kendi sınıfınızdan bir nesneyi doğrudan JSON.generate metoduna verirseniz, temel türlerden biri olmadığı için metin temsili yazılır. Anlamlı bir çıktı için sınıfa to_json(*args) tanımlayıp işi bir hash'e devretmek yaygın bir yoldur. JSON belgesindeki özel ekleme örneği de aynı imzayı kullanır; argümanları aktarmak pretty_generate gibi biçimlendirme seçeneklerinin iç nesnelere ulaşmasını sağlar:
class Urun
def initialize(ad, fiyat)
@ad = ad
@fiyat = fiyat
end
def to_h = {ad: @ad, fiyat: @fiyat}
def to_json(*args) = to_h.to_json(*args)
end
urunler = [Urun.new("Kalem", 15), Urun.new("Defter", 40)]
JSON.generate(urunler)
# => "[{\"ad\":\"Kalem\",\"fiyat\":15},{\"ad\":\"Defter\",\"fiyat\":40}]"
puts JSON.pretty_generate(urunler)
# çıktı:
# [
# {
# "ad": "Kalem",
# "fiyat": 15
# },
# {
# "ad": "Defter",
# "fiyat": 40
# }
# ]Sabit alanlı veri nesneleri için Ruby Struct ve Data yazısındaki to_h yaklaşımı da işinizi görür.
JSON dosyası okumak ve yazmak
JSON.load_file(yol, seçenekler), belgeye göre JSON.parse(File.read(yol), seçenekler) çağrısının kısa yoludur. JSON.dump ise ikinci argüman olarak bir IO nesnesi alırsa JSON metnini doğrudan oraya yazar:
ayar = {sunucu: "127.0.0.1", port: 8080, moduller: ["log", "cache"]}
File.write("ayar.json", JSON.pretty_generate(ayar))
geri = JSON.load_file("ayar.json", symbolize_names: true)
geri # => {sunucu: "127.0.0.1", port: 8080, moduller: ["log", "cache"]}
geri == ayar # => true
File.open("ayar2.json", "w") { |f| JSON.dump(ayar, f) }
File.read("ayar2.json")
# => "{\"sunucu\":\"127.0.0.1\",\"port\":8080,\"moduller\":[\"log\",\"cache\"]}"Dosya modları ve kodlama ayrıntıları için Ruby dosya ve IO işlemleri yazısına bakın.
Ayrıştırma hataları ve JSON::ParserError
Geçersiz bir girdi JSON::ParserError fırlatır. Bu sınıf JSON::JSONError üzerinden StandardError sınıfından türediği için sade bir rescue da yakalar, ama hatayı adıyla yakalamak daha açıktır. Mesajda satır ve sütun bilgisi bulunur:
["{\"a\": 1,}", "", "[NaN]", "{'a': 1}"].each do |bozuk|
JSON.parse(bozuk)
rescue JSON::ParserError => e
puts "#{e.class}: #{e.message}"
end
# çıktı: JSON::ParserError: expected object key, got: '}' at line 1 column 9
# çıktı: JSON::ParserError: unexpected end of input at line 1 column 1
# çıktı: JSON::ParserError: unexpected token 'NaN]' at line 1 column 2
# çıktı: JSON::ParserError: expected object key, got ''a':' at line 1 column 2
JSON::ParserError.ancestors.take(4)
# => [JSON::ParserError, JSON::JSONError, StandardError, Exception]Sondaki virgül, boş metin, NaN ve tek tırnaklı anahtar JSON'da geçersizdir. Dış kaynaktan (örneğin bir API yanıtından) gelen veriyi her zaman rescue JSON::ParserError ile korumanızı öneririz. Rescue sözdizimi için Ruby begin, rescue, ensure yazısına bakın.
Üretim tarafında da hatalar vardır: NaN gibi JSON'da karşılığı olmayan değerler JSON::GeneratorError, izin verilen derinliği aşan iç içe yapılar JSON::NestingError verir:
begin
JSON.generate(Float::NAN)
rescue JSON::GeneratorError => e
puts "#{e.class}: #{e.message}"
end
# çıktı: JSON::GeneratorError: NaN not allowed in JSON
begin
JSON.parse("[[[1]]]", max_nesting: 2)
rescue JSON::NestingError => e
puts "#{e.class}: #{e.message}"
end
# çıktı: JSON::NestingError: nesting of 3 is too deepPratik örnek: dışarıdan gelen bir gövdeyi güvenle okumak
Gerçek projelerde JSON çoğunlukla bir HTTP isteğinin gövdesinden ya da bir kuyruk mesajından gelir. Hem bozuk JSON'u hem de eksik alanları ayrı ayrı ele almak, hataların nedenini anlamayı kolaylaştırır. Aşağıdaki metot zorunlu alan için Hash#fetch, isteğe bağlı alan için varsayılan değer kullanıyor:
def kullanici_oku(govde)
veri = JSON.parse(govde, symbolize_names: true)
{ad: veri.fetch(:ad), eposta: veri[:eposta] || "yok"}
rescue JSON::ParserError
{hata: "geçersiz JSON"}
rescue KeyError => e
{hata: e.message}
end
kullanici_oku('{"ad": "Mehmet", "eposta": "m@ornek.com"}') # => {ad: "Mehmet", eposta: "m@ornek.com"}
kullanici_oku('{"ad": "Zeynep"}') # => {ad: "Zeynep", eposta: "yok"}
kullanici_oku('{"eposta": "x@ornek.com"}') # => {hata: "key not found: :ad"}
kullanici_oku("<html>") # => {hata: "geçersiz JSON"}Metot gövdesinde doğrudan rescue yazmak, ayrı bir begin bloğuna gerek bırakmaz. Hata mesajını kullanıcıya göstermeden önce içinde hassas veri olmadığından emin olun.
Sık kullanılan ayrıştırma seçenekleri

| Seçenek | Varsayılan | Etkisi |
|---|---|---|
| symbolize_names | false | Hash anahtarlarını sembol yapar |
| freeze | false | Dönen nesneleri dondurur |
| max_nesting | 100 | İzin verilen en fazla iç içe derinlik, false ile kapanır |
| allow_nan | false | NaN, Infinity ve -Infinity kabul edilir |
| allow_trailing_comma | false | Sondaki virgüle izin verir |
| allow_control_characters | false | Metin içinde kaçışsız kontrol karakterlerine izin verir |
| object_class, array_class | Hash, Array | Nesne ve diziler için kullanılacak sınıf |
| allow_duplicate_key | belirtilmemiş | Yinelenen anahtarda uyarı, true ile sessiz, false ile hata |
JSON.parse("[1,]", allow_trailing_comma: true) # => [1]
JSON.parse('{"a": 1}', freeze: true).frozen? # => trueYinelenen anahtarlar
Belgeye göre seçenek verilmezse yinelenen anahtarda son değer kullanılır ve kullanımdan kaldırma uyarısı basılır; json 3.0 ile varsayılan davranış hata vermek olacak. Ruby kullanımdan kaldırma uyarılarını varsayılan olarak göstermediği için denememizde uyarıyı Warning[:deprecated] = true ile açtık:
Warning[:deprecated] = true
JSON.parse('{"a": 1, "a": 2}') # => {"a" => 2}
# stderr: warning: detected duplicate key "a" in JSON object. This will raise an error
# in json 3.0 unless enabled via `allow_duplicate_key: true` at line 1 column 1
JSON.parse('{"a": 1, "a": 2}', allow_duplicate_key: false)
# JSON::ParserError: duplicate key "a" at line 1 column 1JSON.load ve güvenlik
Belge, JSON.load metodunun yalnızca kendi veritabanınız gibi güvendiğiniz kaynaklar için düşünüldüğünü, güvenilmeyen kullanıcı verisini buna vermenin tehlikeli olabileceğini açıkça belirtiyor. JSON eklentileri (additions) özelliği de yalnızca güvenilir veriyle kullanılmalı ve kullanımdan kaldırılmış durumda. Dışarıdan gelen veri için JSON.parse tercih edin.
Ruby 4.0 ve json 3.0 yolunda dikkat edilecekler
Ruby 4.0 NEWS dosyası, json varsayılan gem'inin 3.4 ile gelen 2.9.1 sürümünden 2.18.0 sürümüne güncellendiğini listeliyor. Kütüphane belgesi ise ileride gelecek json 3.0 için iki önemli değişikliği şimdiden duyuruyor: yinelenen anahtarlar varsayılan olarak hata verecek ve JSON.load metodunda create_additions varsayılan olarak kapalı olacak. Belgeye göre json 2.8.0 sürümünden beri load, create_additions açıkça etkinleştirilmeden yerel olmayan bir tür üretildiğinde kullanımdan kaldırma uyarısı veriyor. Kodunuzu bugünden JSON.parse ve açık seçeneklerle yazarsanız bu geçiş sizi etkilemez.
Sık Sorulan Sorular
require "json" yazmak zorunlu mu?
Evet. json, Ruby ile gelen bir kütüphane ama çekirdeğin parçası değil; JSON modülünü ve to_json metotlarını kullanmadan önce yüklemeniz gerekir.
Anahtarları metin mi sembol mü almalıyım?
İkisi de çalışır. Veriyi koda yakın, sabit adlı alanlarla kullanıyorsanız symbolize_names: true okunabilirliği artırır. Anahtarlar dışarıdan geliyor ve sayısı belirsizse metin anahtarlar daha güvenli bir varsayılandır.
JSON.generate ile to_json arasında fark var mı?
Temel türlerde sonuç aynıdır. Kendi sınıflarınız için to_json tanımladığınızda JSON.generate da bu metodu kullanır.
CSV verisini JSON'a nasıl çeviririm?
Önce CSV satırlarını hash dizisine dönüştürüp ardından JSON.generate uygularsınız. Format kuralları ve dönüşüm mantığı için CSV formatı ve JSON dönüşümü yazısına bakabilirsiniz.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: Ruby öğrenme rehberi · Ruby Hash metotları · Ruby dosya ve IO işlemleri · Ruby hata yönetimi · CSV ve JSON dönüşümü · Symbol ve String farkı