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
sauce
for theFactoryGirl.build
even 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!