Adventures in HttpContext All the stuff after 'Hello, World'

Machinist 2 + Mongoid + Embeds_Many Goodness

I had a heck of a time getting fixtures working with Mongoid when it came to a required embeds_many property.  No matter what I did, I kept getting an error: “Access to the collection for XXX is not allowed since it is an embedded document, please access a collection from the root document.”

Then I stumbled upon Machinist v2 and the machinist_mongo gem which solved the problem.  And it had a nice API, to boot!

Getting Started

As of this post, you’ll need to pull the machinist_mongo gem directly from git and get the machinist2 branch.  That’s easy with Rails 3:

gem ‘machinist_mongo’, :git => ‘https://github.com/nmerouze/machinist_mongo.git’, :require => ‘machinist/mongoid’, :branch => ‘machinist2′

Next, run

bundle

to update your gems.

I’m using RSpec, so I put my blueprints in the spec/support/ directory so they get automatically loaded. Let’s say I have a User class with a :username and an embeds_many :authentications property (as if you’re following the Railscasts episode on using Devise and Omniauth).  The blueprint will look like this:

Authentication.blueprint do
     uid { "user#{serial_number}" }
     provider { "machinist" }
end

User.blueprint do
     username { "user#{serial_number}" }
     authentications(1) { Authentication.make }
end

My authentications blueprint sets a unique id using the #{serial_number} counter in machinist 2. Then I’m declaring an array of one item in my authentications array, and calling Authentication.make to load the Authentication blueprint. This essentially lazy loads the authentications property via the root document, which is exactly what Mongoid wants, as there’s no Authentications table or root-level document.

Now you can build away using Machinist 2’s User.make (for creating an object without saving it) or make! (which makes and saves the object).