Mongoid: How to Serialize to JSON with a string id attribute

Kartik Jagdale
Aviabird
Published in
3 min readDec 21, 2016

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 idattribute.

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!!!

--

--