Ruby on rails 如何在FactoryBot中设置非';不是外键吗?

Ruby on rails 如何在FactoryBot中设置非';不是外键吗?,ruby-on-rails,ruby,rspec,factory-bot,factory,Ruby On Rails,Ruby,Rspec,Factory Bot,Factory,我正在使用FactoryBot(以前的FactoryGirl)为我的测试创建一些工厂数据。我有一个模型,通过模式(分解为相关内容)看起来像这样: 但是,feature\u id和feature不是对要素对象的引用。。。它们只是线 我对工厂的定义如下: FactoryBot.define do factory :item do team "TheTeam" sequence(:feature_id) {|n| "Feature#{n}" } feature { Fake

我正在使用FactoryBot(以前的FactoryGirl)为我的测试创建一些工厂数据。我有一个模型,通过模式(分解为相关内容)看起来像这样:

但是,
feature\u id
feature
不是对要素对象的引用。。。它们只是线

我对工厂的定义如下:

FactoryBot.define do
  factory :item do
    team "TheTeam"
    sequence(:feature_id) {|n| "Feature#{n}" }
    feature { Faker::Lorem.sentence }
  end
end
> FactoryBot.create(:item, feature_id: "123", feature: "hi")
=> #<Item:0x007fad8d262810
 id: 3,
 team: "TheTeam",
 feature_id: nil,
 feature: nil,
 created_at: Wed, 10 Jan 2018 02:45:01 UTC +00:00,
 updated_at: Wed, 10 Jan 2018 02:45:01 UTC +00:00>
简单的例子是:

> FactoryBot.create(:item)
=> #<Item:0x007fad8cbfc048
 id: 1,
 team: "TheTeam",
 feature_id: "Feature1",
 feature: "Qui voluptatem animi et rerum et.",
 created_at: Wed, 10 Jan 2018 02:40:01 UTC +00:00,
 updated_at: Wed, 10 Jan 2018 02:40:01 UTC +00:00>
您可以看到
功能现在是
nil
。我假设这是因为它试图推断
feature\u id
feature
在某种程度上是相关的。但在这种情况下,我不想让他们这样

是否有更好的方法来定义工厂,使其仅将它们视为不相关的字段?

顺便说一句,如果我试图同时设置
功能\u id
功能
,它看起来是这样的:

FactoryBot.define do
  factory :item do
    team "TheTeam"
    sequence(:feature_id) {|n| "Feature#{n}" }
    feature { Faker::Lorem.sentence }
  end
end
> FactoryBot.create(:item, feature_id: "123", feature: "hi")
=> #<Item:0x007fad8d262810
 id: 3,
 team: "TheTeam",
 feature_id: nil,
 feature: nil,
 created_at: Wed, 10 Jan 2018 02:45:01 UTC +00:00,
 updated_at: Wed, 10 Jan 2018 02:45:01 UTC +00:00>
>FactoryBot.create(:项目,功能\u id:“123”,功能:“hi”)
=> #

所以它只是将两个字段都设置为
nil
。我怀疑FactoryBot试图根据这些字段的名称对其进行“智能化”。我想更改它们,但它们已经在数据库中设置为那样。

看起来FactoryBot正在进行假设,而我还没有找到更改这些假设的方法。也许值得打开一个问题,看看维护人员能提供什么

同时,这里有一个解决方法:

FactoryBot.define do
  FEATURE_IDS ||= (1..1000).cycle

  factory :item do
    team "TheTeam"

    transient { without_feature_id false }
    transient { without_feature false }

    after(:build, :stub) do |item, evaluator|
      item.feature_id = "Feature#{FEATURE_IDS.next}" unless evaluator.without_feature_id
      item.feature = Faker::Lorem.sentence unless evaluator.without_feature
    end
  end
end
在上述情况下,这将正常工作

递增是很棘手的。我无法找到在资源构造上下文之外使用FactoryBot序列的方法,因此我使用枚举器并调用
#next
来创建序列。这类似于FaseYbBOT序列,除了在测试运行期间没有重置为1的方式。

RSpec测试证明,无论我们是在数据库中创建项还是在内存中构建项,它都能按预期工作:

context 'when more than one item is created' do
  let(:item_1) { create(:item) }
  let(:item_2) { create(:item) }

  it 'increments feature_id by 1' do
    expect(item_1.feature_id).to be_present
    expect(item_2.feature_id).to eq(item_1.feature_id.next)
  end
end

context 'when using build instead of create' do
  let(:item_1) { build(:item) }
  let(:item_2) { build(:item) }

  it 'increments feature_id by 1' do
    expect(item_1.feature_id).to be_present
    expect(item_2.feature_id).to eq(item_1.feature_id.next)
  end
end
请注意,如果没有特征id或使用典型构造的特征,则无法创建项目;例如:

>> item = create(:item, feature_id: nil)
将导致

>> item.feature_id
#> "Feature1"
如果要创建不包含feature和feature_id字段的对象,可以执行以下操作:

create(:item, without_feature_id: true, without_feature: true)

如果在FactoryBot之外创建记录,此模型是否按预期工作?例如,如果您执行
Item.create(团队:'TheTeam',feature_id:'123',feature:'Description of feature')
,是否会获得保存了所有属性的记录?好问题,@moveson。是的,它通过控制台工作,只需执行您在那里的操作。我没有任何字段验证,也没有任何关系(此时)。Item类不引用任何其他内容。所以Rails本身也可以使用它。这似乎是Factory中的某个功能。这看起来不错,但是否仍有办法在
after()
块中获取
功能id
序列
部分?这是一个诡辩,但是如果
功能\u id
是一个顺序递增的
功能1
功能2
,诸如此类的
序列
就好了,我非常喜欢它!但是,我认为它可以是这样,而不是提供一个常量:
item.feature\u id=“feature{item.class.count+1}”,除非evaluator.without\u feature\u id
,它只会在项目数上加1。因此,它不会重置,但在其他情况下应该可以工作。它确实会为每次创建添加一个额外的DB调用,但至少现在这不是问题。请记住,您可能不希望每次都在数据库中创建项。通常(希望非常经常)您只想使用
build
build\u stubbed
在内存中构建项。因此,我将避免依赖于数据库的增量值。也就是说,我错说了这个增量变量的工作方式。事实上,它将在测试运行开始时重置,而不是在每个单元测试开始时重置,这在任何情况下都可能是您想要的。。。好电话。是的,让它依赖于DB计数在这方面是有问题的。谢谢需要注意的一件有趣的事情是:如果我将属性更改为
feature\u id
feature\u title
,那么一切都可以在原始设置中运行。所以这肯定是因为
X_id
X
命名模式的缘故。