I have a Family class so defined:
class Family < ActiveRecord::Base
after_initialize :initialize_family
belongs_to :user
validates :user,
:presence => true
validates :name,
:presence => true,
:length => { :maximum => 30 },
:format => { :with => /\A[a-zA-Z0-9\-_\s\']+\z/i}
def initialize_family
if self.name.blank? && self.user
self.name = "#{self.user.profile_full_name}'s Family"
end
end
end
In my factories.rb I have:
Factory.define :family do |f|
f.association :user, :factory => :user
end
In my family_spec.rb I have
let(:family) { Factory(:family) }
But this fails with:
1) Family is valid with valid attributes
Failure/Error: let(:family) { Factory(:family) }
ActiveRecord::RecordInvalid:
Validation failed: Name can't be blank, Name is invalid, Languages can't be blank, Languages is too short (minimum is 1 characters)
# ./spec/models/family_spec.rb:8:in `block (2 levels) in <top (required)>'
# ./spec/models/family_spec.rb:10:in `block (2 levels) in <top (required)>'
Using the debugger I can see that when after_initialize is called self.user is nil. Why is this happening? If I call the family with create or new everything works fine.
Thanks for any help.
This is the answer I got from Joe Ferris:
factory_girl doesn't pass arguments to the constructor. It uses #user= on your model, and instantiates it without any arguments.
and this one from Ben Hughes:
To elaborate on what Joe is saying, after_initialize methods are called immediately upon object initialization, and that time indeed user has not been set.
So for example while this will work:
This will not (which is what factory_girl is doing under the hood):
Just in general you want to be real careful using after_initialize, as remember this is called on every object initialization. A Family.all call on 1,000 objects will cause that to get called 1,000 times.
Sounds like in this instance you might be better of using a before_validation instead of after_initialize.
The following syntax also works for testing in rspec:
Since
after_initialize
is triggered after new objects are instantiated and factory_girl builds instances by callingnew
without any arguments by default, you must useinitialize_with
to overwrite the default build.I believe that it's because the association is lazy, thus in the "after_initialize" there's no user yet.
http://rdoc.info/github/thoughtbot/factory_girl/v1.3.3/file/README.rdoc
Perhaps you can directly call one factory from another, but I didn't try this, e.g.