RubyでのJSONからオブジェクトに変換するっていう話
例えば以下のようにオブジェクトをJSONに出力をするとする
require "json"
require "date"
class Sample
def initialize(params)
@name = params[:name]
@date = params[:date]
end
def to_json(*)
{
name: @name,
date: @date
}.to_json
end
end
puts JSON.generate(
Sample.new(name: "hoge", date: DateTime.now)
)
出力したJSONをファイルに保管しておいて以下のようにロードする
require "json"
class Sample
def initialize(params)
@name = params[:name]
@date = params[:date]
end
def to_json(*)
{
name: @name,
date: @date
}.to_json
end
end
sample = JSON.load_file("sample.json")
はい。ここで問題!変数sampleのクラスはなんでしょう?答えはかんたんで普通にHashです。
そこで今回の件!こうやってパースしたりした際にそういうオブジェクトに変換してほしいよねっていうお話なのですがちゃんとそういう仕組みが用意されているのでご紹介しますw
JSONを出力する側
require "json"
require "date"
class Sample
attr_reader :name, :date
def initialize(params)
@name = params[:name]
@date = params[:date]
end
def to_json(*)
{
JSON.create_id => self.class.name,
name: @name,
date: @date
}.to_json
end
end
puts JSON.generate(
Sample.new(name: "hoge", date: DateTime.now)
)
要点は1つのみto_jsonで出力する際にJSON.create_idを設定しておくこと。それだけ。ということでこれで出力すると
{
"json_class": "Sample",
"name": "hoge",
"date": "2025-06-30T00:00:00+09:00"
}
というような結果になる。でこれをパースする祭にSampleクラスに変換されてほしいよねって言う話なのでそこもやる
出力したJSONを利用する側
require "json"
class Sample
attr_reader :name, :date
def initialize(params)
@name = params[:name]
@date = params[:date]
end
def self.json_create(object)
self.new(name: object["name"], date: object["date"])
end
end
sample = JSON.load_file("sample.json", create_additions: true)
pp sample
# OUTPUT
# #<Sample:0x00007d20eee7e8c0 @date="2025-06-30T00:00:00+09:00", @name="hoge">
要点は以下の2つ
- json_createのクラスメソッドを定義する。そこでJSONをパースしたものからオブジェクトを生成するようにする
- load_file(or parse)にcreate_additionsを指定する
ということなんだが上記のソース中のコメントに記載してる結果を見ればわかるが@dateがDateTimeなどに変換されてなくてただの文字列になってるよね。そこもなんとかしようかと↓
DateTimeとかも変換する方法
require "json"
require "json/add/core"
require "date"
class Sample
attr_reader :name, :date
def initialize(params)
@name = params[:name]
@date = params[:date]
end
def to_json(*)
{
JSON.create_id => self.class.name,
name: @name,
date: @date
}.to_json
end
end
puts JSON.generate(
Sample.new(name: "hoge", date: DateTime.now)
)
require "json/add/coreを追加しただけ。これを実行すると
{
"json_class": "Sample",
"name": "hoge",
"date": {
"json_class": "DateTime",
"y": 2025,
"m": 6,
"d": 30,
"H": 2,
"M": 18,
"S": 6,
"of": "3/8",
"sg": 2299161.0
}
}
というようなJSONが出力される。でこのJSONを解析するには
require "json"
require "json/add/core"
class Sample
attr_reader :name, :date
def initialize(params)
@name = params[:name]
@date = params[:date]
end
def self.json_create(object)
self.new(name: object["name"], date: object["date"])
end
end
sample = JSON.load_file("sample.json", create_additions: true)
pp sample
# OUTPUT
# #<Sample:0x000073c5a9a2f3b8
# @date= #<DateTime: 2025-06-30T00:00:00+09:00 (省略)>,
# @name="hoge">
生成側と同じくrequire json/add/core
を追加しただけ。今回はDateTimeだけを変換しているのでjson/add/date_timeでも可能。必要だと思うものを指定すればいいと思われる(詳しくは以下のURL参照)
https://docs.ruby-lang.org/ja/latest/library/json=2fadd=2fcore.html
まとめ
要点をまとめるとRubyからJSONを出力しそれを利用する場合にオブジェクトに変換したりして欲しい場合には
- 出力するJSONにJSON.create_idを設定する。
- パースする側でオブジェクトに変換するjson_createクラスメソッドを定義する。あとcreate_additionsも設定するのを忘れずに
- DateTimeとかも変換してほしいならrequire
json/add/core
などの拡張ライブラリを使用する
以上!でもRuby特有な機能だと思うのでどうなんだろなってのはちょっと思うけど内部的になんかやる時にJSONで出力してそれを利用する場合とかには使えるかもね(JSON APIとかには×だと思う)
余談:create_additionsオプションについて
generateとparse(or load_file)両方にこのオプションあるがgenerateのcreate_additionsはデフォルトがtrueなのに対しparse(or load_file)ではデフォルトがfalseになっている模様なので(ry