Mongoid: How to Serialize to JSON with a string id attribute
Recently I started working on a project where we are using MongoDB as our Database and we are using Mongoid gem an ODM (Object Document Mapper) Framework for MongoDB in Rails.
However, whenever I tried to serialize any model Object my Ids would be converted into this weird format. Something like below:
"_id": {"$oid":"5858d7a5c8d39c2016331723"}
Which made me really crazy because I didn’t get Id
attribute similar to ActiveRecord which I was really fond of lol. Instead I have “_id” attribute containing “$oid” value.
However, I would prefer something like below:
“id”: “5858d7a5c8d39c2016331723”
So, let’s have a quick look on how to have an “id” attribute in Mongoid Json format.
As we all know upon rails startup all initializers
are loaded and we can configure and override class methods acting upon any Class object.
Yes, this is just what I did.
I created an initializer file named mongoid.rb
in config/initializers/
folder and overrided the to_json
instance method acting upon Mongoid Document Object. Like this:
# config/initializers/mongoid.rb
module Mongoid
module Document
def as_json(options={})
attrs = super(options)
attrs["id"] = attrs["_id"].to_s
attrs
end
end
end
So, you probably till now might have copied the above code and seen that it works. Lol. But, you also mighty be wondering what this code does (for beginners). So let’s see how I did.
As we all knowMongoid: Document
module has a instance method called as_json
which serializes Mongodb Object. Which I needed to override to give me additional id
attribute.
To do this I needed the source of instance method as_json
. Here’s how I found it. I executed the following command which gives the name of the source file that defines the method and the line number where it’s defined. Pretty cool indeed huh!
Mongoid::Document.public_instance_method(:as_json).source_location
For fun you can unchain individual method acting upon mongoid object to see what each method returns.
From above command I received a following output that is the source file location and the line number where the method as_json
is defined.
[.rvm/gems/ruby-2.2.4/gems/mongoid-6.0.3/lib/mongoid/document.rb”, 191]
Upon opening the file I saw the following implementation of as_json
instance method.
#.rvm/gems/ruby-2.2.4/gems/mongoid-6.0.3/lib/mongoid/document.rbdef as_json(options = nil)
if options && (options[:compact] == true)
super(options).reject! { |k,v| v.nil? }
else
super(options)
end
end
As we see it returns super(options)
, which means it uses the parent implementation of this method which traces back us to the original ruby implementation of as_json
which acts upon a Hash
of values.
If you want to see the original implementation and details of to_json
ruby method you can visit the below link and see the source code.
Link: http://apidock.com/rails/Hash/to_json
In short, all it does is takes a Hash and converts each key in Hash to string and returns the entire Hash in string format.
So, Coming Back to our Overridden Mongoid to_json
implementation. Where all I needed to was add an extra id
attr in Mongoid Object which originally deep down is a Hash. Extract the value from our little weirdo Mongoid _id
(which BTW is a BSON::ObjectId
, Just FYI) and assign it to our new pretty clean id
key and return the entire object, Just like this:
...
attrs = super(options)
attrs[“id”] = attrs[“_id”].to_s
attrs
...
And Hurray We are Done !!!
So Now you might have understood how to debug, trace back , override and customize global Mongoid:Document instance methods.
If you liked this article, click the like button below.
For more musings about programming, follow me here or on twitter so you’ll get notified when I write new posts.
See Ya!!!