Embedding objects with Fabrication in Rails 3.1
Sidenote from 2021: original URL for this post was http://zombie-storage.com/?p=79
This post is about Ruby on Rails 3.1 testing with RSpec. It’s a bit of a departure from my usual content but it is my $dayjob and this will be helpful to folk out there struggling along on the intertubes. This post also assume you know a lot of background information about Ruby, Rails, testing and Fabrication.
Fabrication is a great gem. I use it with RSpec and Cucumber because it works with Mongoid and seems less buggy than some of the other object generation frameworks. One issue I’ve had with it is how to create embedded objects which you should be using if you have nested forms. Nested object should definitely be tested, doubly so if you have any special validations running. So here is how to write a Fabricator that actually embeds objects.
These are some example objects for a user who speaks languages. The user.rb model
class User
include Mongoid::Document
field :languages
embeds_many :languages
validates_presence_of :languages
attr_accessible :languages_attributes
accepts_nested_attributes_for :languages,
:reject_if => lambda { |a| a[:language].blank? },
:allow_destroy => true
end
The language.rb model
class Language
include Mongoid::Document
field :known_language
field :proficiency
key :language
embedded_in :user
attr_accessible :language, :proficiency
end
The Fabricators. Remember that Fabricators have a special directory layout. Mine are in spec/fabricators/ then a folder with the same name as the model for each Fabricator.
The language fabricator (spec/fabricator/language/fabricator.rb)
Fabricator(:language) do
known_language "en-US"
proficiency "1"
end
The user fabricator (spec/fabricator/user/fabricator.rb)
Fabricator(:user) do
languages { [ Fabricate.build(:language,
:known_language => "en-US",
:proficiency => "1"),
Fabricate.build(:language,
:known_language => "ko-KR",
:proficiency => "1") ] }
end
A dodgy test user_spec.rb file
require 'spec_helper'
describe User do
describe "a user with two langauges" do
it "should be allowed to enter the world" do
two_language_knowing_user = Fabricate.build(:user)
two_language_knowing_user.should be_valid
end
it "should know two langauges" do
two_language_knowing_user = Fabricate.build(:user)
two_language_knowing_user.languages.count.should == 2
end
end
end
Works like a boss. Jawsome.