How to fabricate Mongoid document with embedded document using Fabrication?
Asked Answered
T

1

11

I use Mongoid and Fabrication gems. I have switched to Mongoid.rc7 from beta20 and now I can't fabricate document with embedded document:

#Models
class User
  include Mongoid::Document
  embeds_many :roles
end

class Role
  include Mongoid::Document
  field :name, :type => String
  embedded_in :user, :inverse_of => :roles
end

#Fabricators
Fabricator(:role) do
  name { "role" }
end

Fabricator(:user) do
  email                 { Faker::Internet.email }
  password              { "password" }
  password_confirmation { |user| user.password }
  roles { [] }
end

Fabricator(:admin_user, :from => :user) do
  roles(:count => 1) { |user| Fabricate(:role, :user => user, :name => "admin") }
end

When I try to fabricate admin_user I get user without roles. When I try to fabricate role, I get an error.

#<User _id: 4d62a2fd1d41c87f09000003, email: "[email protected]", encrypted_password: "$2a$10$r9I0Aeu5KPVKqq2rHRl3nuYpvohlB2XdrH6nB/K8XL21pCEHt8l6u", remember_created_at: nil, reset_password_token: nil, failed_attempts: 0, unlock_token: nil, locked_at: nil, sign_in_count: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil>
>>u.roles
[]
>>r = Fabricate(:role)
Mongoid::Errors::InvalidCollection: Access to the collection for Role is not allowed since it is an embedded document, please access a collection from the root document.

With Mongoid.beta20 this worked as I expected. Does anybody know how to fabricate Mongoid.rc7 document with embedded document using Fabrication?

Tunnage answered 21/2, 2011 at 17:44 Comment(1)
You can tag fabrication now with your rep :)Giles
T
22

This is a working solution for embeds_many with Mongoid.rc7:

Fabricator(:admin_user, :from => :user) do
  after_create { |user | user.roles << Fabricate.build(:role, :name => "admin") }
end

For embeds_one this code works (address embeds one location):

Fabricator(:address) do
  location { |address| Fabricate(:location, :address => address) }
end
Tunnage answered 27/2, 2011 at 8:6 Comment(3)
Using build as in Fabricator.build was key for me getting fabricator to persist the embeds_one (cascade_callbacks: true) ) correctly.Emileemilee
Thanks for the answer. However, using after_build instead after_create is a better approach. When Fabricate.build(:admin_user) is called it fills address whereas after_create does not.Cenac
Found that if I did not use Fabricate.build then I was getting some validation errors from the 'mother' object (the admin_user in this case) when trying to persist it. Not sure why?Bluet

© 2022 - 2024 — McMap. All rights reserved.