我的问题似乎很常见,但我在文档或互联网本身没有找到任何答案。
这似乎是这个问题has_many while respecting build strategy in factory_girl的一个克隆,但是在工厂发生了2年之后,工厂改变了很多。
我有一个名为照片的has_many关系模型。我想填充这个有很多关系,保留了我对构建策略的选择。
如果我致电offering = FactoryGirl.build_stubbed :offering, :stay
,我希望offering.photos
成为存根模型的集合。
我发现实现这一目标的唯一方法是:
factory :offering do
association :partner, factory: :named_partner
association :destination, factory: :geolocated_destination
trait :stay do
title "Hotel Gran Vía"
description "Great hotel in a great zone with great views"
offering_type 'stay'
price 65
rooms 70
stars 4
event_spaces 3
photos do
case @build_strategy
when FactoryGirl::Strategy::Create then [FactoryGirl.create(:hotel_photo)]
when FactoryGirl::Strategy::Build then [FactoryGirl.build(:hotel_photo)]
when FactoryGirl::Strategy::Stub then [FactoryGirl.build_stubbed(:hotel_photo)]
end
end
end
end
无需说IT必须存在更好的方法。
想法?
答案 0 :(得分:10)
您可以使用各种FactoryGirl回调:
factory :offering do
association :partner, factory: :named_partner
association :destination, factory: :geolocated_destination
trait :stay do
title "Hotel Gran Vía"
description "Great hotel in a great zone with great views"
offering_type 'stay'
price 65
rooms 70
stars 4
event_spaces 3
after(:stub) do |offering|
offering.photos = [build_stubbed(:hotel_photo)]
end
after(:build) do |offering|
offering.photos = [build(:hotel_photo)]
end
after(:create) do |offering|
offering.photos = [create(:hotel_photo)]
end
end
end
答案 1 :(得分:9)
以下是Flipstone答案的稍微清洁版本:
factory :offering do
trait :stay do
...
photos do
association :hotel_photo, :strategy => @build_strategy.class
end
end
end
答案 2 :(得分:3)
您也可以直接调用FactoryRunner类并将构建策略传递给它使用。
factory :offering do
trait :stay do
...
photos do
FactoryGirl::FactoryRunner.new(:hotel_photo, @build_strategy.class, []).run
end
end
end
答案 3 :(得分:1)
其他答案有缺陷,反向关联未正确初始化,例如offering.photos.first.offering == offering
是false
。更糟糕的是,offering
是每个Offering
的新photos
。
另外,明确指定策略是多余的。
克服流程并简化事情:
factory :offering do
trait :stay do
...
photos do
association :hotel_photo, offering: @instance
end
end
end
@instance
是工厂正在创建的Offering
的一个实例。对于好奇,上下文是FactoryGirl::Evaluator
。
如果你不像我一样喜欢@instance
,你可以查看evaluator.rb
并找到以下内容:
def method_missing(method_name, *args, &block)
if @instance.respond_to?(method_name)
@instance.send(method_name, *args, &block)
我真的很喜欢itself
的样子:
factory :offering do
trait :stay do
...
photos do
association :hotel_photo, offering: itself
end
end
end
能够使用itself
,在Evaluator
上取消定义:
FactoryGirl::Evaluator.class_eval { undef_method :itself }
它将传递给@instance
并返回@instance
本身。
为了提供包含多张照片的完整示例:
factory :offering do
trait :stay do
...
photos do
3.times.map do
association :hotel_photo, offering: itself
end
end
end
end
用法:
offering = FactoryGirl.build_stubbed :offering, :stay
offering.photos.length # => 3
offering.photos.all? { |photo| photo.offering == offering } # => true
小心,有些事情可能无法正常工作:
offering.photos.first.offering_id
令人惊讶的是nil
; offering.photos.count
将使用SELECT COUNT(*) FROM hotel_photos ...
命中数据库(在大多数情况下会返回0),请在断言中使用length
或size
。答案 4 :(得分:0)
这种事对我有用:
factory :offering do
trait :stay do
...
photos { |o| [o.association(:hotel_photo)] }
end
end