在 Rails 6 和 FactoryGirl 4.9 中,如何将原始对象与正在创建的 has_many 关系联系起来?

In Rails 6 and FactoryGirl 4.9, how do I tie the original object back its has_many relation that's being created?

我正在使用 Rails 6 和 FactoryGirl 4.9.0。我有这些模型,一个有一个 has_many 和另一个 …

class Contract < ApplicationRecord
    …
  belongs_to :client

class Client < ApplicationRecord
    …
  has_many :contracts

在我的工厂里,我有

FactoryGirl.define do
  factory :client do
    name "Test Client”
  end

  factory :dp_client, class: Client do

    Contracts { [create(:contract)] }

  end
end

但是当我去使用工厂的时候,

create(:dp_client)

我收到错误消息……

Validation failed: Client must exist

在我的工厂中创建“has_many”关系时,我是否将它与创建它的对象联系起来?

是这样完成的:

FactoryBot.define do
  factory :client do
    name { "Test client" }
  end

  factory :contract do
    association :client
  end

  factory :dp_client, class: Client do
    name { "Test DP Client"}
    contracts { [ FactoryBot.create(:contract) ]}
  end
end

FactoryBot.define do
  factory :client do
    name { "Test client" }
  end

  factory :contract do
   client
  end

  factory :dp_client, class: Client do
    name { "client name" }
    after(:create) do |client|
      create(:contract, client: client)
    end
  end
end

有多种方法可以解决这个问题。

选项 1:

使用您所在街区的实例。 FactoryBot 已将 self 设置为工厂,并将其作为参数传入。所以这两个都应该有效:

contracts { |factory| [build(:contract, client: factory.instance)] }

# or

contracts { [build(:contract, client: instance)] } # because self is the factory

注意:我在这里使用 build 而不是 create 因为 Rails 如何自动保存关联。在大多数用例中,两者都应该可以正常工作。

选项 2:使用 after_create

这是Saiqul Haq提出的解决方案。主要缺点:它只适用于 create(不适用于 build)。另外值得注意的是:它可能无法反映您的应用程序的真实情况(例如,如果您的记录总是一起创建的)。

选项 3:使用 before_create

与之前的解决方案类似,但在工作流程方面可能更现实:

before(:create) do |client|
  client.build_contract(attributes_for(:contract))
end