I have been struggling on this for a couple days. I have this model:
class BusinessEntity < ActiveRecord::Base
has_many :business_locations
accepts_nested_attributes_for :business_locations, :allow_destroy => true,
:reject_if => proc { |attributes| attributes.all? { |key, value| key == '_destroy' || value.blank? } }
after_initialize :build_child
....
def build_child
self.business_locations.build if self.business_locations.empty?
end
business_entites.rb (factory)
FactoryGirl.define do
factory :business_entity do
name "DaveHahnDev"
association :company, :factory => :company
association :default_currency, :factory => :currency
factory :business_entity_with_locations do
after(:build) do |business_entity|
business_entity.class.skip_callback(:create, :after, :set_primary_business_info)
business_entity.business_locations << FactoryGirl.build(:business_location)
end
end
end
factory :business_location do
name "Main Office"
business_entity
address1 "139 fittons road west"
address2 "a different address"
city { Faker::Address.city }
province "Ontario"
country "Canada"
postal_code "L3V3V3"
end
end
Now when I call FactoryGirl.create(:business_entity) in a spec I get valdation error on business_locations have blank attributes. This is the child initialized by the after_initialize callback. I thought the reject_if would take care of this, as it does if you use the application from a browser. If i add:
before_validation :remove_blank_children
def remove_blank_children
self.business_locations.each do |bl|
bl.mark_for_destruction if bl.attributes.all? {|k,v| v.blank?}
end
end
everything will pass fine, but I feel like I should not need to do this.
Is it possible I am testing this wrong, or is it bad practice to build children in the models.
Any thoughts will be a great help.
is it bad practice to build children in the models
Not necessarily, but I’d avoid
after_initialize—it is executed on every instantiation of your model, even a straightfind.I think you’d be better off isolating the cases where you need to add a business_location and doing it explicitly. And as it seems that your
business_entity_with_locationsfactory is doing exactly that, I’m not sure why you need the callback at all.As for why the
accepts_nested_attributes_foris not working, I believe that is because you are not using it. It expects an attribute hash like:{ :business_locations => { 0 => { :name => “Sample Name } } }
to be passed into a method like
new. That’s not what you’re doing—you’re callingbuildon the association without any parameters. So the attribute-setter logic provided byaccepts_nested_attributes_foris never invoked.