正如戴夫所指出的,使用瞬态属性是一种选择。另一种选择是通过nil
建设相关工厂时。
FactoryGirl:避免关联之间的循环/无限循环
让我用一个例子来说明:
FactoryGirl.define do
factory :user do
sequence(:name) { |n| "Julio Jones-#{n}"}
sequence(:email) { |n| "julio.jones-#{n}@atl.com" }
# we pass user: nil here because it will cause the identity factory
# to just skip the line user { ... }.
identity { build(:identity, user: nil) }
end
factory :identity do
# we pass user: nil here because it will cause the user factory
# to just skip the line idenitity { ... }.
user { build(:user, identity: nil) }
provider "Google"
email "[email protected] /cdn-cgi/l/email-protection"
password "password"
end
end
当我们打电话时build(:user)
,代码最终到达以下行:
identity { build(:identity, user: nil) }
这称为身份工厂。当它到达通常会构建用户关联的行时(user { build(:user, identity: nil) }
),它会跳过它,因为 user 已被设置(为零)。恭喜,您刚刚避免了循环依赖!
当你打电话时它的工作方式是一样的build(:identity)
.
FactoryGirl:从关联工厂中的一个工厂访问属性
最后一件事:在您的情况下,您需要访问身份工厂中用户的电子邮件属性。在您的代码示例中,您说:
factory :identity do
...
email { user.email }
end
显然,当我们调用时会失败build(:user)
因为当我们调用身份工厂时,我们将 user 设置为 nil。不要害怕!当我们调用身份工厂时,我们只需传递一个新的用户对象和电子邮件即可。所以该行变为:
identity { build(:identity, user: User.new(email: email)) }
这既可以防止循环、无限的关联循环,也可以确保电子邮件属性在身份工厂中可用。
最后,您的代码将如下所示:
FactoryGirl.define do
factory :user do
sequence(:name) { |n| "Julio Jones-#{n}"}
sequence(:email) { |n| "julio.jones-#{n}@atl.com" }
# we pass user: User.new here because it will...
# a) cause the identity factory to skip the line user { ... } and
# b) allow us to use the email attribute in the identity factory.
identity { build(:identity, user: User.new(email: email)) }
end
factory :identity do
# we pass user: nil here because it will cause the user factory
# to just skip the line idenitity { ... }.
user { build(:user, identity: nil) }
provider "Google"
email { user.email }
password "password"
end
end
希望它有帮助!