如何为具有通常由嵌套属性克服的验证的has_one/belongs_to关系的模型创建工厂?

Ben*_*nns 3 validation ruby-on-rails factory-bot

我有一个具有用户模型的帐户模型,以及属于帐户模型的用户模型.我认为演示所需的基本代码是:

class Account < ActiveRecord::Base
  has_one :user
  validates_presence_of :user
  accepts_nested_attributes_for :user
end

class User < ActiveRecord::Base
  belongs_to :account
  # validates_presence_of :account # this is not actually present,
                                   # but is implied by a not null requirement
                                   # in the database, so it only takes effect on
                                   # save or update, instead of on #valid?
end
Run Code Online (Sandbox Code Playgroud)

当我在每个工厂中定义关联时:

Factory.define :user do |f|
  f.association :account
end

Factory.define :account do |f|
  f.association :user
end
Run Code Online (Sandbox Code Playgroud)

我得到一个堆栈溢出,因为每个都是递归创建一个帐户/用户.

我能够解决这个问题的方法是在我的测试中模拟嵌套的属性表单:

before :each do
  account_attributes = Factory.attributes_for :account
  account_attributes[:user_attributes] = Factory.attributes_for :user
  @account = Account.new(account_attributes)
end
Run Code Online (Sandbox Code Playgroud)

但是,我想将这个逻辑保留在工厂中,因为一旦我开始添加其他模块,它就会失控:

before :each do
  account_attributes = Factory.attributes_for :account
  account_attributes[:user_attributes] = Factory.attributes_for :user
  account_attributes[:user_attributes][:profile_attributes] = Factory.attributes_for :profile
  account_attributes[:payment_profile_attributes] = Factory.attributes_for :payment_profile
  account_attributes[:subscription_attributes] = Factory.attributes_for :subscription
  @account = Account.new(account_attributes)
end
Run Code Online (Sandbox Code Playgroud)

请帮忙!

Ben*_*nns 7

我能够通过使用factory_girl的after_build回调来解决这个问题.

Factory.define :account do |f|
  f.after_build do |account|
    account.user ||= Factory.build(:user, :account => account)
    account.payment_profile ||= Factory.build(:payment_profile, :account => account)
    account.subscription ||= Factory.build(:subscription, :account => account)
  end
end

Factory.define :user do |f|
  f.after_build do |user|
    user.account ||= Factory.build(:account, :user => user)
    user.profile ||= Factory.build(:profile, :user => user)
  end
end
Run Code Online (Sandbox Code Playgroud)

这将在保存拥有类之前创建关联的类,因此验证通过.