FactoryBot - 覆盖与特征

时间:2018-06-05 15:36:22

标签: ruby-on-rails factory-bot

假设我有几个模特,运动和运动员,其中有belongs_to运动员和运动has_many运动员。然后,我为这两个创建工厂,如下所示:

FactoryBot.define do
  factory :player do
    name "John Doe"
    sport

    trait :with_existing_sport do
      transient do
        sport Sport.last
      end

      sport { with_existing_sport }
    end
  end
end

FactoryBot.define do
  factory :sport do
    name "football"
  end
end

当我打开rails控制台并运行FactoryBot.create(:player)时,它可以正常工作并在数据库中创建一个新的播放器和相关的运动。但是当我运行FactoryBot.create(:player, :with_existing_sport)时,我希望它能够创建播放器,然后将该播放器与Sport.last相关联,但它会返回:

FactoryBot::AttributeDefinitionError: Attribute already defined: sport

总而言之,我想要完成的是能够:

  • FactoryBot.create(:player)应创建一个玩家和一项运动
  • FactoryBot.create(:player, :with_existing_sport)应该创建一个播放器并使其属于Sport.last
  • FactoryBot.create(:player, with_existing_sport: Sport.first)应该创建一个播放器并使其属于Sport.first

有办法做到这一点吗?我在文档中找不到任何内容。

*编辑*

溶液

感谢Marlin Pierce,我最终得到了这样的工作:

FactoryBot.define do
  factory :player do
    name "John Doe"
    sport

    trait :with_existing_sport do
      transient do
        associated_sport Sport.last
      end

      sport { associated_sport }
    end
  end
end

FactoryBot.define do
  factory :sport do
    name "football"
  end
end

现在我可以按如下方式使用工厂:

  • FactoryBot.create(:player),它将创建一个玩家,并且它是相关的运动
  • FactoryBot.create(:player, :with_existing_sport)将创建播放器并将其与Sport.last
  • 相关联
  • FactoryBot.create(:player, :with_existing_sport, associated_sport: Sport.find_by(name: "football"))会将其与associated_sport
  • 相关联

1 个答案:

答案 0 :(得分:2)

我想你想要:

FactoryBot.define do
  factory :player do
    name "John Doe"
    sport

    trait :with_existing_sport do
      sport { Sport.last }
    end
  end
end

如果您确实需要瞬态属性,则应将其重命名为与非瞬态字段不同的内容。

trait :with_existing_sport do
  transient do
    sport_trans Sport.last
  end

  sport { sport_trans }
end