FactoryGirl:填充有许多关系保持构造策略(FactoryGirl: Populate a

2019-08-02 12:26发布

我的问题似乎很常见,但我还没有发现的文档或Internet本身的任何答复。

这似乎这个问题的一个副本,同时尊重建立战略factory_girl的has_many但2,5年该职位factory_girl后发生了很大变化。

我有一个的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

没必要说,它必须存在一个更好的方式做到这一点。

想法?

Answer 1:

这里的Flipstone的回答稍微清洁的版本:

factory :offering do
  trait :stay do
    ...
    photos do
      association :hotel_photo, :strategy => @build_strategy.class
    end
  end
end


Answer 2:

您可以使用各种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


Answer 3:

您也可以直接调用FactoryRunner类,并把它传递给使用构造策略。

factory :offering do
  trait :stay do
    ...
    photos do
      FactoryGirl::FactoryRunner.new(:hotel_photo, @build_strategy.class, []).run
    end
  end
end


Answer 4:

其他答案有一个缺陷,逆协会没有被正确初始化,如offering.photos.first.offering == offeringfalse 。 更糟的是不正确而,该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),请使用lengthsize的断言。


Answer 5:

这种事情对我的作品:

factory :offering do
  trait :stay do
    ...
    photos { |o| [o.association(:hotel_photo)] }
  end
end


文章来源: FactoryGirl: Populate a has many relation preserving build strategy