Reputation: 15471
Broken Case
I have the following class
class Vehicle < ActiveRecord::Base
belongs_to :manufacturer
belongs_to :production_plant
before_save :delegate_audit_number
attr_accessible :manufacturer_id, :production_plant_id, :audit_number
private
def delegate_audit_number
self.audit_number ||= self.manufacturer.audits.last.try(:number)
end
end
and the following factory
FactoryGirl.define do
factory :vehicle do
association :production_plant, factory: :production_plant
after(:validation) do |v|
v.manufacturer_id = v.production_plant.manufacturer_id
end
end
end
Then calling FactoryGirl.create(:vehicle)
fails in the before_save
with
Failure/Error: @vehicle = FactoryGirl.create(:vehicle)
NoMethodError:
undefined method `audits' for nil:NilClass
By debugging, I have discovered two things:
1) the manufacturer method is nil
in the before_save
callback
2) The after_validation
callback is never hit.
Working Case
Identical in every way to the broken case, except the before_save is moved out into an observer
class AuditNumberObserver < ActiveRecord::Observer
observe :vehicle
def before_save(entity)
entity.audit_number ||= entity.manufacturer.audits.last.try(:number)
end
end
Now it is my understanding (based on the following list in the documentation: http://guides.rubyonrails.org/v3.2.9/active_record_validations_callbacks.html#available-callbacks )
That after_validation
should happen before before_save
Why is factory girl not respecting the callback chain in the first case? Why is factory girl respecting the callback chain in the second case? What is the difference?
Upvotes: 0
Views: 232
Reputation: 2353
I think your problem is the use of after(:validation)
in the factory.
According to FactoryGirl's README, this callback is not defined by the gem.
Upvotes: 1