Machinist 2 + Mongoid + Embeds_Many Goodness
Dec 10 2010I 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).