I've got these 5 models: Guardian, Student, Relationship, RelationshipType and School. Between them, I've got these associations
class Guardian < ActiveRecord::Base
belongs_to :school
has_many :relationships, :dependent => :destroy
has_many :students, :through => :relationships
end
class Student < ActiveRecord::Base
belongs_to :school
has_many :relationships, :dependent => :destroy
has_many :guardians, :through => :relationships
end
class Relationship < ActiveRecord::Base
belongs_to :student
belongs_to :guardian
belongs_to :relationship_type
end
class School < ActiveRecord::Base
has_many :guardians, :dependent => :destroy
has_many :students, :dependent => :destroy
end
class RelationshipType < ActiveRecord::Base
has_many :relationships
end
I want to write a FactoryGirl which defines a relationship. Every relationship must have a guardian and a student. These two must belong to the same school. The guardian factory has an association with school, and so does the student factory. I've been unable to get them to be built in the same school. I've got the following code:
FactoryGirl.define do
factory :relationship do
association :guardian
association :student, :school => self.guardian.school
relationship_type RelationshipType.first
end
end
This results in the following error when I try to build a relationship using this factory:
undefined method `school' for #<FactoryGirl::Declaration::Implicit:0x0000010098af98> (NoMethodError)
Is there any way to do what I want, to make the guardian and the student belong to the same school without having to resort to passing already created guardians and students to the factory (which is not its purpose)?
This answer is the first result on Google for 'factory girl shared association' and the answer from santuxus really helped me out :)
Here's an update with the syntax from the latest version of Factory Girl in case anyone else stumbles across it:
FactoryGirl.define do
factory :relationship do
guardian
relationship_type RelationshipType.first
after(:build) do |relationship|
relationship.student = FactoryGirl.create(:student, school: relationship.guardian.school) unless relationship.student.present?
end
end
end
The unless
clause prevents student
from being replaced if it's been passed into the factory with FactoryGirl.create(:relationship, student: foo)
.
I think this should work:
FactoryGirl.define do
factory :relationship do
association :guardian
relationship_type RelationshipType.first
after_build do |relationship|
relationship.student = Factory(:student, :school => relationship.guardian.school)
end
end
end
There is cleaner way to write this association. Answer got from this github issue.
FactoryGirl.define do
factory :relationship do
association :guardian
student { build(:student, school: relationship.guardian.school) }
relationship_type RelationshipType.first
end
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With