Forging Forgecraft: A Hybrid SQL MongoDB Data Solution

January 7, 2012

[][1][Forgecraft][1] is a game currently in development using Ruby on Rails, Backbone.js, and all sorts of HTML5 buzzwords. Read an introduction [here][2], and play the demo [here][1].

One of my primary goals while building Forgecraft is to learn as many new technologies as possible. I’ve learned the hard way that it’s better to leave this kind of exploration in your hobby projects and out of your production “for real” stuff. And, seeing as how there are so many emergent technologies right now in web development there’s a lot to explore!

Whole Hog is Too Much Hog

[MongoDB][3] has quite a bit of steam behind it in the Rails/Ruby community (and plenty of other places too), and with projects like [Mongoid][4] and [MongoMapper][5] (I went with Mongoid) it’s an easy drop-in replacement for Active Record that maintains all those ORM conventions you know and love. I decided against the replacement approach for one primary reason: I wanted to use existing, robust, and actively developed libraries that rely on Active Record.

Example: There’s no reason to roll your own authentication/user system when there are insanely popular and feature-full libraries already in place for them like [Devise][6] and [authlogic][7] (I went with Devise).

Fortunately combining Active Record with Mongoid and getting the best of both worlds proved to be easy and painless.

The Set Up

The [instructions][8] for Mongoid include a step to remove the Active Record libraries from being loaded and delete your database.yml. Simply skip that step and both systems will run in conjunction.

One small operational change you’ll have to make during development is explicitly defining when your rails generators should use Active Record. If you want to make an AR-driven model, your generators will look like:

rails g active_record:model Player … produces a model the extends from ActiveRecord::Base.

And by default, the data generators will use Mongoid:

rails g model Skill … produces a model that includes Mongoid::Document.

The Implementation

Here’s how this combo system really shines in my opinion: get all the great features of gems built on AR with all the schema less features of Mongo. I’ll walk through an example:

In Forgecraft, the authenticating object is the Player and players have many Skills which, right now, are Accuracy, Craftsmanship, and Perception. But, the skill list will likely grow and change over time as the game evolves. A typical AR/SQL based approach would be to create a skills table and a join table between players and skills resulting in a complex multi-table query to get a player’s complete skills.

It’s clear here that the Player and Skills would fit well together as a single document in Mongo, queried all at once in one tidy object. But, since the Player is also our authentication model, using Mongo would prevent us from using Devise to handle all of that boring and complex auth stuff for us.

Enter Hybridization. Forgecraft’s implementation uses the typical Devise set up around the Player object (again all on top of AR). All of a player’s skills go into a single document with a reference to the player, like so: