Rails HABTM in Mongoid & Factory Girl

In Rails say you have a HABTM (N:N) relationship between two models

class User
has_and_belongs_to_many :posts

class Post
has_and_belongs_to_many :users

So what essentially it means is a Post can have many Authors and an Author can have multiple posts.
Now you want to test drive the thing by seeding test data in Factory Girl.

Here is an article for seeding data for 1:N relationships in Factory girl. But it doesn’t talk about HABTM relations.

I was playing around with factory girl and figured out a way to seed a post with authors.
Here is how you do it –

Factory.define :user, :class=>User do |user|
user.first_name "Alex"
user.last_name "Malcolm"
user.nick_name "Alexy"
user.email "alexy.m@gmail.com"
user.password "foobar"
user.password_confirmation "foobar"
user.role "author"

Factory.define :post do |post|
post.title "Foo Post"
post.content "Bar content"

Factory.define :post_with_author, :parent => :post do |post|
post.after_create { |p| Factory(:user, :posts => [p]) }

Now in your Test class do
@post = Factory(:post_with_author)

Factory girl would have inserted the User for you and then a Post and updated the relationship.

Btw I the code above was tested in Mongoid/MongoDB and not on Active Record. But since its working in Mongoid there is no reason I see why it won’t work with Active Record natively.

Another thing which I found with Mongoid/MongoDB and HABTM is that unlike Active Record you don’t need a Join Table like Users_Posts – the reason being MongoDB doesn’t support join queries. So you have to lump the join table into the respective models.

The Mongoid stores HABTM relation in back-end something like this

> db.users.find()
{ "_id" : ObjectId("4dc2010ea38c3d0b50000003"), "first_name" : "Alex", "last_name" : "Malcolm", "nick_name" : "Alexy", "post_ids" : [
], "role" : "author" }

That is in the Users model you have an array of post_ids and similarly in the Posts Model you will have an array of user_ids.

And finally if its on Active Record it may be preferable to have has_many :through instead of has_and_belongs_to_many relation as this post says.