Rails - Create Object from nested hash of JSON data by dry-struct
Now I am wondering to migrate a gem virtus to other new gem. And I tried dry-struct and dry-types. Here is the result of creating Rails Model Object from nested hash of JSON data.
What I would like to do
I prepared a sample data as below. The data is like JSON data and it has nested struct. Then the final expected result is to have auther object(Auther Class) and books objects(Array[Book Class]).
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
My environment
Rails 6.0.2
Ruby 2.5.7
Install dry-struct
At first, let's install gem dry-struct. It will install other related gems such as dry-types.
gem 'dry-struct', '~> 0.5.0'
bundle install
Initial setting
follow the way that the official document instruct.
dry-rb.org
create new file types.rb at initializers like below.
module Types include Dry.Types() end
Create Classes
Create three classes Author, Book, and GetAuthorInfo. All of them has to be inherited by Dry::Struct.
class Book < Dry::Struct attribute :id, Types::String attribute :name, Types::String attribute :publishedyear, Types::String def title_call "The name of the book is" + name + "." end end
class Author < Dry::Struct attribute :id, Types::String attribute :name, Types::String def my_name "My name is" + 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
Usage
Let's use it. When get JSON data and parse it to hash(need to symbolize it) and put it to initial value of the GetAuthorInfo class, the nested object will be created!
parsed_data = JSON.parse(json_data, symbolize_names: true) autherInfo = GetAuthorInfo.new(parsed_data) autherInfo.auther.myname
Ofcourse you can call method of the class from the object. Try more.
autherInfo.books.size
autherInfo.books[1].title_call
Wonderfull!
Thank you for reading by post.