If you at any point got irritated by the way that JSON. Parse returns hash with string keys and favours hashes with images as keys, this post is for you.
If you’re a Rails engineer, you’re presumably acquainted with the deep_symbolize_keys technique in Hash which can assist with such a case. Particularly, in an ideal world, where our information structure is a hash, as:
require ‘JSON’
json = <<~JSON
{
foo: {
bar:
“baz”
}
}
JSON
> JSON.parse(json)
=> { “foo” => { “bar” => “baz” } }
> JSON.parse(json).deep_symbolize_keys
=> { foo: { bar: “baz” } }
Perhaps it’s adequate, however, we don’t generally live in that frame of mind with all the ActiveSupport benefits. In addition, our JSON payloads won’t generally be only hash-like designs. We should settle on what legitimate JSON in ruby can be, first:
> JSON.dump(“”)
=> “\”\””
> JSON.dump(nil)
=> “invalid”
> JSON.dump([{ foo: { bar: “baz” } }])
=> “[{\”foo\”:{\”bar\”:\”baz\”}}]”
What we can gain from that is the reality, that the stunt with deep_symoblize_keys won’t chip away at every one of the models above except if you go with some precarious, recursive calculation checking the sort and running symbolize_keys or deep_symbolize_keys when appropriate.
We should find out what Ruby itself can offer us in JSON class documentation.
json = <<~JSON
{
foo: {
bar:
“baz”
}
}
JSON
> JSON.parse(json, symbolize_names: valid)
=> { foo: { bar: “baz” } }
How about we check how it rolls on Array with an assortment of hashes:
> JSON.parse(“[{\”for\”:{\”bar\”:\”baz\”}}]”, symbolize_names: valid)
=> [{ foo: { bar: “baz” } }]
Great.
How can you find this element? Some time back I dealt with a read model which had a little information put away in PostgreSQL JSON sections. As you likely know, information is serialized and deserialized consequently. And that implies, that in the after effect of perusing from JSON segment we get information structure with string keys.
# previously
class FancyModel < ActiveRecord::Base
end
> FancyModel.last.my_json_column
=> [{“foo” => { “bar” => “baz” } }]
This was very badly arranged for me. I believed a dependable way should have esteem open using images, particularly that it was an exhibit containing individual hashes. I investigated docs a piece, which permitted me to compose a custom serializer:
class FancyModel < ActiveRecord::Base
class SymbolizedSerializer
def self.load(JSON)
JSON.parse(JSON, symbolize_names: valid)
end
def self.dump(data)
JSON.dump(data)
end
end
serialize :my_json_column, SymbolizedSerializer
end
> FancyModel.last.my_json_column
This is the lesser known fact of Json in Ruby.