Reputation: 422
I can't seem to get FactoryGirl to call my before_add callback with an associated model.
I've got a Course model with:
has_many :lessons, dependent: :destroy, before_add: :set_lesson_number
def set_lesson_number
#stuff
end
a Lesson model with:
belongs_to :course
.
a Lesson factory with:
FactoryGirl.define do
factory :lesson do
course
end
end
and a Course factory, defined as suggested by the Factory Girl wiki:
FactoryGirl.define do
factory :course do
factory :course_with_lessons do
transient do
lessons_count 10
end
after(:create) do |course, evaluator|
create_list(:lesson, evaluator.lessons_count, course: course)
end
end
end
end
The before_add callback doesn't get called when I do FactoryGirl.create(:lesson)
, but it does get called if I do this:
lesson = FactoryGirl.build(:lesson)
course = lesson.course
course.lessons << l
In both cases, course.lessons ends up including lesson.
By the same token, FactoryGirl.build(:course_with_lessons)
doesn't work with the above Course factory, but if I replace the create_list line with:
evaluator.lessons_count.times do
course.lessons << build(lesson)
end
it does. It seems like FactoryGirl is creating the Lessons and setting their Course ID's, but somehow not actually "adding" them to the collection, so I have to do it manually.
Am I missing something about how FactoryGirl is supposed to work? Or about how ActiveRecord works?
Upvotes: 0
Views: 196
Reputation: 4486
This is how ActiveRecord
works.
If you run the following in your rails console
you'll see the before_add
callback on the association is not called:
course = Course.create
Lesson.create(course_id: course.id)
I imagine FactoryGirl.create_list
generates objects in a similar way.
The lesson
needs to be added to the collection in order for the callback to fire. This can be done in a couple of ways.
1. Create a Lesson
through course
course.lessons.create
2. Explicitly add the lesson
to course.lessons
course.lessons << lesson
3. Explicitly add a collection of lesson
to course.lessons
course.lessons = [lesson1, lesson2]
To get the callback to fire, you could modify your factory like so:
factory :course do
factory :course_with_lessons do
transient do
lessons_count 10
end
after(:create) do |course, evaluator|
course.lessons =
build_list(:lesson, evaluator.lessons_count, course: course)
course.save
end
end
end
Hope that helps.
Upvotes: 2