What object can I serialize in ActiveRecord? - ruby-on-rails

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)

Related

JSON Deserialization in Ruby

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

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.

Difference on working of object_id method with Fixnum object and String object

I am confused about the working of one of the innate method present in all ruby objects i.e object_id method. When I run object_id method on any Fixnum object again and again, for example in irb if I do this,
>>100.object_id
=>201
and do this again,
>>100.object_id
=>201
But when I work with String object for example
>>"Hello".object_id
=>162333336
and do this again,
>>"Hello".object_id
=>15502236
Why so? In ruby, everything is an object, and every object has an innate method named object_id which uniquely identifies the object. But here, ruby is confusing me as it treats two strings with same text (i.e "Hello") as different, but two Fixnum objects with same value (i.e.100) as the same and gives the same object id for them. Why so? Can any one please help me?
Fixnums are immutable objects in Ruby. There is exactly one instance created and you work with that object "directly". i.e references are not used unlike other regular objects. So They have a fixed object_id. This is ok because you have only one instance of the object.
But when you write "hello", a new string object is created. And in the same script, if you give another "hello", even though they have same content, a new object is created. Hence the different object_ids.
Such behaviour is a matter of Ruby implementation, not specification. Most likely, you're using MRI (compiled from C source), in JRuby you can get different results.
For performance purposes, MRI handles true, false, nil, Fixnum and symbol specially. A couple of links where you can find more info about it: http://www.oreillynet.com/ruby/blog/2006/02/ruby_values_and_object_ids.html , http://rhg.rubyforge.org/chapter02.html
If you wants to get same object id of string you have to convert it to symbol first then your object_id remains constant
'Hello'.to_sym.object_id

Convert any record to a string and back?

How can I convert any record type to a single String and back? Perhaps load the record into a stream and read it as a String? The records I'm using won't have any special types included - they're just using simple things like String, Integer, PChar, DWORD, and Array of [String], etc. and nothing like classes or functions.
This string will further be saved into various places, such as a flat text file, database record, sent over the network, etc. The string contents may be transferred by other means between each of these, such as copying the string from a text file and saving it to a database record. The general idea is that the string will be compatible enough to save anywhere, move it around, and load it back in to its original state. I do understand I need to be able to recognize what type of record it is and assign it accordingly, and that part I don't need help with.
You can serialize your record using the RTTI, from here you can use XML, JSON or other format to persist the record data.
If you don't want write your own method to serialize the records try these alternatives.
superobject (using the TSuperRttiContext class you can serialize a record to JSON)
TKBDynamic
SynCommons unit from Synopse.
XmlSerial unit (Object and Record Serialization and De-serialization to XML) from Robert Love

Seed embedded documents to MongoDB using Rails rake db:seed

How should db.seeds be structured in order to provide data for MongoDB, especially when containing embedded documents?
I ran into the following error when trying to seed a supposedly wrongly structured db.seeds file :
Cannot serialize an object of class ClassName into BSON.
Start by creating a 'new' nested object like address, with attribute street and city, and setting it equal to a variable. Then create the parent object, in this case user with an attribute address, and assign the variable you created above to it. Since it is a nested object, you need to wrap your variable in an array []. Doing it this way will make it easy to read especially if you have a lot of nested objects. When referencing the nested object make sure to exclude any spaces after the colon or you will get an error.
a = Address.new(street: 'Any_Street', city: 'Any_City')
User.create(address:[a])
This will seed mongoDB with an address object which is nested in the user object.
Parent.create(title: 'foo', children: [
Child.create(title: 'bar', date: Time.utc(2011,10,13)),
Child.create(...),
Child.create(...)
])

Resources