factory_bot
factory_bot copied to clipboard
has_many relations
I'd like to be able to clearly, safely, and idiomatically create an object and its many relations. For example:
new_author = create(:author)
distinguished_author = create(:author, with_article_count: 3)
assert_equal new_author.articles.count, 0
assert_equal distinguished_author.articles.count, 3
The above can currently be done using a transient property and some hooks, but it's kinda kludgy and hard to get right. Let's make this somewhat common case easier and less error prone.
It could look like this:
FactoryBot.define do
factory :author do
association(:article, relation: :has_many)
end
end
Or it could allow overrides:
FactoryBot.define do
factory :author do
association(:unique_article, relation: :has_many) do |user, offset|
title { "How to win, part #{offset + 1}" } # sets the title for the article
end
end
end
This would be pretty great. If pursued, I would suggest the api look more like the current *[strategy]_list pattern rather than passing in a relation argument. That is:
association_list(:article, 1)
I typically use a transient association count to avoid duplication & allow count overrides. Something like:
factory :author do
transient do
article_count { 0 }
end
articles do
Array.new(article_count) { association :article, author: instance }
end
trait :with_article do # typically use this trait, but could pass in article_count
article_count { 1 }
end
end
such cases could look like this:
factory :author do
transient do
article_count { 0 }
end
articles do
association_list :article, article_count, author: instance
end
trait :with_article do
article_count { 1 }
end
end
(I think the last bit about an override block seems like a separate concern... better handled by the association factory it is calling.)