JSON Deserialization in Ruby - ruby-on-rails

Is there a JSON Deserialization equivalent of Java's Google JSON in Ruby. With-out the necessity of defining any custom serializer or deserializer for each class, one can write a one-line code to convert JSON string into custom Java class as shown here under.
Address address=gson.fromJson(addressJsonStringForm, Address.class);
To accomplish this , one need-not put any annotations/interfaces in Address class nor write separate Deserializer utility for every class that we need to deserialize. This makes it very easy to deserialize/serialize classes from third party libraries. There are quite a lot of options on whether to serialize nulls / include /exclude certain attributes etc. I 'm looking for such a versatile JSON from and to custom object serialization/deserialization utility in Ruby. I 'm new to Ruby.
Reference:
https://dzone.com/articles/deserializing-json-java-object

You can convert it into a Hash using the JSON module:
require 'json'
hash = JSON.parse('{"age":18, "name":"Vinicius"}')
hash["age"]
=> 18
If you want to convert it to a "structured" object, you can use OpenStruct:
require 'json'
require 'ostruct'
person = JSON.parse('{"age":18, "name":"Vinicius"}', object_class: OpenStruct)
person.name
=> "Vinicius"
An OpenStruct is a data structure, similar to a Hash, that allows the definition of arbitrary attributes with their accompanying values. This is accomplished by using Ruby's metaprogramming to define methods on the class itself. (docs)
OpenStruct may help you if you don't always know the JSON keys, as it dynamically creates an object.

jsonapi-rb
DeserializablePost.call(json_hash)
roar
song = Song.new(title: "Medicine Balls")
SongRepresenter.new(song).from_json('{"title":"Linoleum"}')
song.title #=> Linoleum
Netflix - fast_jsonapi
json_string = MovieSerializer.new(movie).serialized_json

Related

Extend array without creating new class in Rails 4

I am using an API and receiving a array of hashes. Lets say:
array = client.getObjects(123) //where 123 is some collection of object ID
I want to add some additional attributes to the array to use later in my view, like:
<%= array.getRequestor %> // return a string
What is the easiest way to do this? I was thinking about creating a new class that extends array but I wanted to know can I just add a string "requestor" attribute a lot easier?
Thanks
Extending a core class is not a good idea in general, especially when the additional responsibilities you want to add in are specific to your functional domain.
6 months down the line, somebody (perhaps yourself) will be trying to debug the code and wondering why does Array expose a random custom method.
It would be better to explicitly define your custom view object, perhaps by using a Struct, eg:
# my_view_object.rb
class MyViewObject < Struct.new(:hash)
def getRequestor
# manipulate / return specific hash data
end
end
# controller
#view_obj = MyViewObject.new(client.getObjects(123))
# view
#view_obj.hash # original hash
#view_obj.getRequestor # your custom attribute
Note that the intent of a Struct is to represent a custom data structure, not behaviour. If your custom method needs to do unrelated work, you might want to use a PORO (Plain Old Ruby Object) instead.
I'd say that extending Array sounds like a really bad idea. I would suggest you instead wrap the array in hash of your own. For example
my_hash = {getRequestor: ?, array: array}
and then use it like
<%= my_hash.getRequestor %>
as in your example code.

how to parse json from ActiveModel::Serializer back into objects

I've got a bunch of serializers. Now I'd like to turn the JSON back into the original objects for testing. I don't see a way to do that with ActiveModel::Serializers. Looks like there used to be an from_json method that was deprecated. How are you supposed to do this?
Basically I want to test the round tripping like this:
json = WidgetSerializer.new(#widget).to_json
testw = Widget.new
testw.from_json(json) #from_json doesn't exist in ActiveModel::Serializers
#widget.should == testw
But the "from_json" method on the model doesn't properly read the json from the serializer because its not in the expected format
The best I can think of is using either Widget.find() or Widget.find_by(), depending on the attributes you pass to your serializer (and especially if one of them is a unique attribute)
For example if your serializer includes id (the simplest in your case) :
json = WidgetSerializer.new(#widget).to_json
target_id = JSON.parse(json)[:id]
test_widget = Widget.find(target_id)
#widget.should == test_widget

What object can I serialize in ActiveRecord?

I'm using serialize :my_array, Array and serialize :my_hash, Hash quite happily to store settings and arrays in the database conveniently.
Which other objects can I use this way? I know I can use Struct and OpenStruct for instance, but how would I know if an object can be serialized this way with ActiveRecord? For instance, how do I know if I can use the class Set (which should have been called UniqArray, mind you) this way?
This code determines a coder for serialization in Rails' serialize method:
if [:load, :dump].all? { |x| class_name.respond_to?(x) }
class_name
else
Coders::YAMLColumn.new(class_name)
end
That means in short: a Object can be serialized if the Object itself has the methods load and dump. Or if YAML can load and dump the Object. Check it this way:
object == YAML.load(YAML.dump(object)) # with require 'yaml' in irb
Serializing in AR uses Psych for dumping instances into yaml string.
Psych in turn knows how to serialize all objects inherited from Object (it's almost all objects in Ruby).
In general case, Psych takes all instance variables of object and dumps those as yaml fields.
There are also special cases for dumping several classes, such as Array, Class, Date, DateTime, Exception, FalseClass, Float, Hash, Integer, Module, NilClass, Range, Rational, Regexp, String, Struct, Symbol, Time, TrueClass, and some other rarely used.
As example, if we have class UniqArray < Set, and instance UniqArray.new([1,2,3]) - dumped string will be "--- !ruby/object:UniqArray\nhash:\n 1: true\n 2: true\n 3: true\n" (where hash is an instance variable name which implements set store)

How to get back DateTime from JSON.decode

Are there any alternatives to JSON.decode (or any options to it I'm not aware of) that will parse the JSON with the date/time strings converted to DateTime objects?
ActiveSupport::JSON.decode({date_time: DateTime.now()}.to_json)
Having to
h["dt1"] = DateTime.strptime(h["dt1"])
h["dt2"] = DateTime.strptime(h["dt2"])
For each of the DateTime fields is quite annoying.
Or are there any other ways to serialize ruby objects as a string to store in redis and then get back the original object and their members as original objects?
Would Masrhal.dump and Marshal.load be preferred? Not sure why the redis-rb docs suggest JSON.
Unfortunately the JSON specification does not include a Date/Time data type.
You could use Marshal but that would limit you to only use ruby to write/read from redis. Perhaps a better option would be YAML, which does have a Date/Time type.

Serializing JSON with configured serializer

I am using ASP.Net Web API with JSON.Net to serialize. I had to configure the serializer to handle ISO dates properly like this:
var iso = new IsoDateTimeConverter {
DateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.fffK"
};
GlobalConfiguration.Configuration.Formatters.JsonFormatter
.SerializerSettings.Converters.Add(iso);
This works fine when I am passing my objects down via the WebAPI. My problem, however, is that I have another place where I want to explicitly call the serialization:
#Html.Raw(JsonConvert.SerializeObject(Model));
In this case, it doesn't use the configuration I set up. I am aware that I can pass the iso converter into the SerializeObject call, but I prefer to avoid this and get a hold of a configured serialzer for obvious reasons.
Any ideas?
If you're going to do JSON serialization yourself, you have to pass the settings you want explicitly. There's no way around it. The best I can think of if you want to reuse the same serializer settings is to do something like this:
JsonConvert.SerializeObject(Model, GlobalConfiguration.Configuration.Formatters.
JsonFormatter.SerializerSettings)

Resources