Suppose you are creating a record which holds a Sauce and percentages or ingredients that must add up to 100%. You have the parent record, the Sauce and the children Sauce Components.
Tips on Using Factory Girl to Create a Record with Mandatory Children
This article has the right format which is not what you’d expect
FactoryGirl.define do
factory :recipe do
name 'Secret Sauce'
after_build do |sauce|
sauce << FactoryGirl.build(:sauce_component, percentage: 0.60, sauce: sauce)
sauce << FactoryGirl.build(:sauce_component, percentage: 0.40, sauce: sauce)
end
end
end
Note:
- The use of the
<< - The inclusion of the
saucefor theFactoryGirl.buildeven though we’re using<< - The use of
after_build
Validate presence of the belongs_to foreign key with the object, not the id
Use the association not the association_id when doing validations for presence in Rails! Otherwise, the validator complains the id doesn’t exist, and you can’t get FactoryGirl to save the parent record.
Thus, the right validation in the SauceComponent model is
validates :sauce, presence: true
This one prevents the FactoryGirl syntax from running, because the sauce_id is nil at first, so the records don’t save. Don’t do this one!
validates :sauce_id, presence: true
And it’s SUPER important to specify the has_many and belongs_to using the inverse_of parameter.
- http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html
- http://stackoverflow.com/a/12271748/1009332
Otherwise, you’ll have issues with validating for the presence of the Sauce in the SauceComponent because they get created at the same time.
Accepts Nested Attributes
This article is helpful:
http://homeonrails.com/2012/10/validating-nested-associations-in-rails/
When displaying 2 levels of nesting, it’s incredibly important to check for sauce_component.object.marked_for_destruction? when looping through the child records:
= f.simple_fields_for :sauce_components do |sauce_component|
- unless sauce_component.object.marked_for_destruction?
= render 'sauce_component_fields', :f => sauce_component
Otherwise, if you get a validation error, you’ll display the record that you deleted, which is very confusing!