Ruby objects and JSON serialization (without Rails)
Solution 1
For the JSON library to be available, you may have to install libjson-ruby
from your package manager.
To use the 'json' library:
require 'json'
To convert an object to JSON (these 3 ways are equivalent):
JSON.dump object #returns a JSON string
JSON.generate object #returns a JSON string
object.to_json #returns a JSON string
To convert JSON text to an object (these 2 ways are equivalent):
JSON.load string #returns an object
JSON.parse string #returns an object
It will be a bit more difficult for objects from your own classes. For the following class, to_json will produce something like "\"#<A:0xb76e5728>\""
.
class A
def initialize a=[1,2,3], b='hello'
@a = a
@b = b
end
end
This probably isn't desirable. To effectively serialise your object as JSON, you should create your own to_json method. To go with this, a from_json class method would be useful. You could extend your class like so:
class A
def to_json
{'a' => @a, 'b' => @b}.to_json
end
def self.from_json string
data = JSON.load string
self.new data['a'], data['b']
end
end
You could automate this by inheriting from a 'JSONable' class:
class JSONable
def to_json
hash = {}
self.instance_variables.each do |var|
hash[var] = self.instance_variable_get var
end
hash.to_json
end
def from_json! string
JSON.load(string).each do |var, val|
self.instance_variable_set var, val
end
end
end
Then you can use object.to_json
to serialise to JSON and object.from_json! string
to copy the saved state that was saved as the JSON string to the object.
Solution 2
Check out Oj. There are gotchas when it comes to converting any old object to JSON, but Oj can do it.
require 'oj'
class A
def initialize a=[1,2,3], b='hello'
@a = a
@b = b
end
end
a = A.new
puts Oj::dump a, :indent => 2
This outputs:
{
"^o":"A",
"a":[
1,
2,
3
],
"b":"hello"
}
Note that ^o
is used to designate the object's class, and is there to aid deserialization. To omit ^o
, use :compat
mode:
puts Oj::dump a, :indent => 2, :mode => :compat
Output:
{
"a":[
1,
2,
3
],
"b":"hello"
}
Solution 3
If rendering performance is critical, you might also want to look at yajl-ruby, which is a binding to the C yajl library. The serialization API for that one looks like:
require 'yajl'
Yajl::Encoder.encode({"foo" => "bar"}) #=> "{\"foo\":\"bar\"}"
Solution 4
What version of Ruby are you using? ruby -v
will tell you.
If it's 1.9.2, JSON is included in the standard library.
If you're on 1.8.something then do gem install json
and it'll install. Then, in your code do:
require 'rubygems'
require 'json'
Then append to_json
to an object and you're good to go:
asdf = {'a' => 'b'} #=> {"a"=>"b"}
asdf.to_json #=> "{"a":"b"}"
Solution 5
Since I searched a lot myself to serialize a Ruby Object to json:
require 'json'
class User
attr_accessor :name, :age
def initialize(name, age)
@name = name
@age = age
end
def as_json(options={})
{
name: @name,
age: @age
}
end
def to_json(*options)
as_json(*options).to_json(*options)
end
end
user = User.new("Foo Bar", 42)
puts user.to_json #=> {"name":"Foo Bar","age":42}
BuddyJoe
I like to code C# and work with the web. Still learning.
Updated on July 05, 2022Comments
-
BuddyJoe almost 2 years
I'm trying to understand the JSON serialization landscape in Ruby. I'm new to Ruby.
Is there any good JSON serialization options if you are not working with Rails?
That seems to be where this answer goes (to Rails) How to convert a Ruby object to JSON
The json gem seems to make it look like you have to write your own to_json method. I haven't been able to get to_json to work with arrays and hashes (documentation says it works with these) Is there a reason the json gem doesn't just reflect over the object and use a default serialization strategy? Isn't this how to_yaml works (guessing here)
-
BuddyJoe over 13 yearsWas looking for a library that didn't require you to write the to_json method on classes. Is there a class you can inherit from that gives you this via reflection? and works on complex objects?
-
BuddyJoe over 13 yearsI'm looking at the way the YAML code in the stdlib works, but that is little bit much for me to grok at this point.
-
Ernest over 13 yearsAs I will have to work with a lots of JSON data in my next project, this can be my life saver. +1
-
Ernest over 13 yearsWill it be quicker than yajl?
-
PJP over 13 yearsThat's for you to determine using
Benchmark
isn't it? -
Ernest over 13 yearsI Thought you maybe know this. Benchmarked and it is slower :P Particularly when encoding.
-
Redoman over 11 yearsAre you guys sure there is not an easier way ?
-
epzee over 11 yearsTo remove the @ from the property name: hash[var.to_s.delete "@"]
-
markus_p over 11 yearshey david4dev, i took your example and added some functionality to support also nested classes. check it out github.com/MarkusPfundstein/JSONable
-
Martin about 11 yearsVery explicit and clear explanation. Helped me, and I'm sure will be useful to others.
-
Kelvin almost 11 yearsWarning:
JSON.parse
andJSON.load
are not equivalent.load
can be a security risk. Also,parse
accepts a String but cannot accept an IO for example. -
thinkOfaNumber over 10 yearswhen I create a to_json method on a class it needs one parameter which is of type: JSON::Ext::Generator::State. This appears to be options for formatting the json (ruby-doc.org)
-
redolent over 10 yearsThis doesn't work:
in `to_json': wrong number of arguments (1 for 0) (ArgumentError)
-
ashes999 over 9 yearsJsonable appears defunct: last updated in 2012, and the example code fails --
JSON.parse
returns json, not an object. -
ashes999 over 9 years
Oj
has great compatibility for changing classes and deserializing them without additional errors. +1 -
dentarg over 9 yearsDon't know about the examples, but I found Jsonable perfect for my use case: feedjira.herokuapp.com github.com/dentarg/feedjira.herokuapp.com/blob/… github.com/dentarg/feedjira.herokuapp.com/blob/…
-
ashes999 over 9 yearsMaybe it's dependent on Rails or something else. I'm using straight Ruby.
-
dentarg over 9 yearsMe too, not using Rails.
-
randall over 8 years@redolent - that a rails thing appearantly. use
to_json(options={})
to fix. see stackoverflow.com/questions/11599610/… -
Matthew Kraus over 7 yearsI copied/pasted this into a ruby file, and it executed without a problem. It might be helpful to update your answer to include the output: {"name":"Foo Bar","age":42}
-
kkost over 7 yearsHow to remove this "^oj" value ?
-
Database over 7 years@neustart47: I've edited my answer to show how this can be done, using the
:compat
mode.