高木のブログ

【Ruby/Rails】JSONのキーをキャメルケースからスネークケースに、文字列からシンボルに変換する

2021/03/03

問題

APIを叩いて返ってきたレスポンスがJSON形式でキーがキャメルケースの文字列だった
普通にJSON.parseしても問題ないが、Rubyだったらできればスネークケースのシンボルで扱いたい

SwitchBotのAPIレスポンス

devices.json
{
    "statusCode": 100,
    "body": {
        "deviceList": [
            {
                "deviceId": "500291B269BE",
                "deviceName": "Living Room Humidifier",
                "deviceType": "Humidifier",
                "enableCloudService": true,
                "hubDeviceId": "000000000000"
            }
        ],
        "infraredRemoteList": [
            {
                "deviceId": "02-202008110034-13",
                "deviceName": "Living Room TV",
                "remoteType": "TV",
                "hubDeviceId": "FA7310762361"
            }
        ]
    },
    "message": "success"
}

JSON.parseした結果

JSON.parse(File.open('devices.json').read)
#=> {"statusCode"=>100, "body"=>{"deviceList"=>[{"deviceId"=>"500291B269BE", "deviceName"=>"Living Room Humidifier", "deviceType"=>"Humidifier", "enableCloudService"=>true, "hubDeviceId"=>"000000000000"}], "infraredRemoteList"=>[{"deviceId"=>"02-202008110034-13", "deviceName"=>"Living Room TV", "remoteType"=>"TV", "hubDeviceId"=>"FA7310762361"}]}, "message"=>"success"}

解決方法

deep_transform_keys(&:underscore)でスネークケースにして、deep_symbolize_keysでシンボルにする

require 'json'
require 'active_support/all' # Rubyの場合

JSON.parse(File.open('devices.json').read).deep_transform_keys(&:underscore).deep_symbolize_keys
#=> {:status_code=>100, :body=>{:device_list=>[{:device_id=>"500291B269BE", :device_name=>"Living Room Humidifier", :device_type=>"Humidifier", :enable_cloud_service=>true, :hub_device_id=>"000000000000"}], :infrared_remote_list=>[{:device_id=>"02-202008110034-13", :device_name=>"Living Room TV", :remote_type=>"TV", :hub_device_id=>"FA7310762361"}]}, :message=>"success"}

解説的なもの

キーを文字列からシンボルにする方法

方法は2つある

JSON.parseのsymbolize_namesオプション

JSON.parse('{"name": "Takagi"}', symbolize_names: true)
#=> {:name=>"Takagi"}

symbolize_keysメソッド

JSON.parse('{"name": "Takagi"}').symbolize_keys
#=> {:name=>"Takagi"}

※多次元の場合はdeep_symbolize_keys

キーをキャメルケースからスネークケースにする方法

JSON.parse('{"lastName": "Takagi"}').transform_keys(&:underscore)
#=> {"last_name"=>"Takagi"}

※多次元の場合はdeep_transform_keys

symbolize_namesオプションを使わず、symbolize_keysメソッドを使った理由

Symbolクラスにunderscoreメソッドが存在しないため

JSON.parse(File.open('spec/support/fixtures/devices.json').read, symbolize_names: true).deep_transform_keys(&:underscore)
#=> NoMethodError (undefined method `underscore' for :statusCode:Symbol)

Written by ytkg, Twitter, GitHub

Pixela