みずラテ

牛乳と水を2対1で。

【Rails】JSONデータをhashにしてdry-structでオブジェクト化する

Rails初心者なので他にいい方法がある気がするのですが、最新知ったやり方をまとめてみます。

やりたいこと

APIなどで取得したJSONデータをそのままRubyのオブジェクトに落とし込んで処理に使いたい。

やり方

今回はDry-rbシリーズというGemの中のdry-structとdry-typesを駆使して実装したいと思います。

環境

Rails 6.0.2
Ruby 2.5.7

dry-structのインストール

Gemfileに以下を追記してbundle installしましょう。
勝手にdry-typesやその他必要な関連Gemも一緒にインストールされると思います。

gem 'dry-struct', '~> 0.5.0'

bundle install

初期設定

dry-rb.org
こちらのサイトにあるようにどこかに初期設定を入れる必要があります。
私は、initializers配下に新規にtypes.rbを作成して配置しました。

module Types
  include Dry.Types()
end

データの準備

今回簡単なテストデータとしてこんなものを用意しました。
何かしらのAPIをコールしたら、レスポンスbodyにステータスと、著者と代表作が3冊取得できたという想定です。
booksの部分がネストしているというのがミソです。

json_data = <<EOS
{
  "status": "0",
  "message": "",
  "author": {
    "id": "auther111",
    "name": "akutagawa"
  },
  "books": [
    {
      "id": "book111",
      "name": "rasho-mon",
      "publishedyear": "1915"
    },
    {
      "id": "book222",
      "name": "kumonoito",
      "publishedyear": "1918"
    },
    {
      "id": "book333",
      "name": "ababababa",
      "publishedyear": "1923"
    }
  ]
}
EOS

クラスを作成する

作るクラスは3つ。Author, Book, そして2つをまとめたGetAuthorInfoというクラスです。
全てのクラスでdry-structを使うので、Dry::Structを継承します。

class Book < Dry::Struct
  attribute :id, Types::String
  attribute :name, Types::String
  attribute :publishedyear, Types::String
  def title_call
    "この本は、" + name + "だよ。"
  end
end

class Author < Dry::Struct
  attribute :id, Types::String
  attribute :name, Types::String
  def my_name
    "私の名前は、" + name + "である。"
  end
end

class GetAuthorInfo < Dry::Struct
  attribute :status, Types::String
  attribute :message, Types::String
  attribute :author, Author
  attribute :books, Types::Array.of(Book)
end

使ってみる

JSONデータをhash化するのは標準のparseメソッドで。
気をつけなきゃいけないのは、hash化するときのキーは文字列ではなくて、シンボルにする必要があるというところ。(dry-structの仕様です。)
あとは、パースしてhash化されたものを引数にnewしてあげると、オブジェクトになっています。

parsed_data = JSON.parse(json_data, symbolize_names: true)
autherInfo = GetAutherInfo.new(parsed_data)
autherInfo.auther.myname

ネストしていた部分はbookオブジェクトとして配列から取り出せるようになっていますし、配列として.sizeなんかも普通にできます。

autherInfo.books.size
autherInfo.books[1].title_call

以上です

全然dry-rbのサンプル出てこないから大変でした。JSONデータをrubyオブジェクトとしてRailsで使用するのって普通どうやってやっているんだろう。

とりあえず今回は以上です。

Ruby on Rails 6 実践ガイド impress top gearシリーズ

Ruby on Rails 6 実践ガイド impress top gearシリーズ

  • 作者:黒田 努
  • 発売日: 2019/12/20
  • メディア: Kindle版