Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

Ruby: JSON.parseのあまり知られていない機能(翻訳)

概要

原著者の許諾を得て翻訳・公開いたします。

参考: 週刊Railsウォッチ20211110

Ruby: JSON.parseのあまり知られていない機能(翻訳)

RubyのJSON.parseが文字列キーのハッシュを返すことにうんざりしたことのある方、シンボルキーのハッシュが欲しい方、本記事は皆さんのためにあります。

こんなときは、Rails開発者ならおそらくご存知のHashdeep_symbolize_keysメソッドが使えます。特に理想の世界では、データ構造が以下のようなハッシュになっています。

require 'json'

json = <<~JSON
{
  foo: {
    bar:
      "baz"
  }
}
JSON

> JSON.parse(json)
=> { "foo" => { "bar" => "baz" } }

> JSON.parse(json).deep_symbolize_keys
=> { foo: { bar: "baz" } }

おそらくこれで足りると思いますが、私たちはRailsの世界だけで生きているわけではないので、いつもActive Supportが助けに来てくれるとは限りません。さらに、JSONのペイロードが単純なハッシュ的構造になっているとも限りません。有効なJSONフォーマットにはこんなものもあるのです。まずは1つ目。

> JSON.dump("")
#=> "\"\""

> JSON.dump(nil)
#=> "null"

> JSON.dump([{ foo: { bar: "baz" } }])
#=> "[{\"foo\":{\"bar\":\"baz\"}}]"

deep_symoblize_keysの技は、そのままでは上のどれにも通用しないという事実を思い知らされます。型を再帰的にチェックするトリッキーなアルゴリズムを書いて、可能な場合にはsymbolize_keysdeep_symbolize_keysを適用するなら別ですが。

それでは、Ruby自身が提供するJSONクラスのドキュメントをみっちり読んでみましょう。

json = <<~JSON
{
  foo: {
    bar:
      "baz"
  }
}
JSON

> JSON.parse(json, symbolize_names: true)
=> { foo: { bar: "baz" } }

ハッシュのコレクションを持つArrayではどうなるかも調べてみましょう。

> JSON.parse("[{\"foo\":{\"bar\":\"baz\"}}]", symbolize_names: true)
=> [{ foo: { bar: "baz" } }]

完璧です。

私がこの機能をどうやって見つけたかですか?少し前に、PostgreSQLのjsonカラムにデータを保存する読み取り用モデルで作業していたときのことです。ご存知のようにこのデータは自動的にシリアライズ/デシリアライズされます。つまりjsonカラムから読み込んだ結果は、以下のように文字列キーを持つデータ構造になります。

# 以前の実装
class FancyModel < ActiveRecord::Base
end

> FancyModel.last.my_json_column
=> [{"foo" => { "bar" => "baz" } }]

これは自分にとって相当不便でしたので、シンボルで値にアクセスできる信頼性の高い方法が欲しくなりました。とくにこの場合は、ハッシュを要素に含む配列だったのです。ドキュメントを少し読み進めた結果、以下のようなカスタムのシリアライザを書くことに成功しました。

class FancyModel < ActiveRecord::Base
  class SymbolizedSerializer
    def self.load(json)
      JSON.parse(json, symbolize_names: true)
    end

    def self.dump(data)
      JSON.dump(data)
    end
  end

  serialize :my_json_column, SymbolizedSerializer
end

> FancyModel.last.my_json_column
#=> [{foo: { bar: "baz" } }]

RubyのJSONクラスに隠れているこの機能はあまり知られていないように思います。本記事がお役に立ちましたら、お気軽にシェアしてください。

お知らせ

ARKADEMY.DEVに参加してArkencyのトップクラス教育プログラムコースにアクセスしましょう!「Railsアーキテクトマスタークラス」「アンチ"IF"コース」「忙しいプログラマーのためのブログ執筆コース」「Async Remoteコース」「TDD動画クラス」「ドメイン駆動Rails動画コース」以外にもさまざまなコースが新設中です。

関連記事

Rails: Value Objectで「基本データ型への執着」と戦う(翻訳)


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。