如何在工厂女孩中创建 has_and_properties_to_many 关联

考虑到以下情况

class User < ActiveRecord::Base
has_and_belongs_to_many :companies
end


class Company < ActiveRecord::Base
has_and_belongs_to_many :users
end

你如何定义公司和用户的工厂,包括双向协会? 这是我的尝试

Factory.define :company do |f|
f.users{ |users| [users.association :company]}
end


Factory.define :user do |f|
f.companies{ |companies| [companies.association :user]}
end

now I try

Factory :user

当工厂递归地使用彼此来定义自己时,这可能会导致一个无限循环,这也许并不令人惊讶。

More surprisingly I haven't found a mention of how to do this anywhere, is there a pattern for defining the necessary factories or I am doing something fundamentally wrong?

47475 次浏览

首先,我强烈建议您使用 has _ many: through 代替 habtm (关于这个 给你的更多信息) ,这样您最终会得到如下内容:

Employment belongs_to :users
Employment belongs_to :companies


User has_many :employments
User has_many :companies, :through => :employments


Company has_many :employments
Company has_many :users, :through => :employments

After this you'll have has_many association on both sides and can assign to them in factory_girl in the way you did it.

工厂女孩已经更新,现在包括回调解决这个问题。看看 http://robots.thoughtbot.com/post/254496652/aint-no-calla-back-girl了解更多信息。

What worked for me was setting the association when using the factory. Using your example:

user = Factory(:user)
company = Factory(:company)


company.users << user
company.save!

我无法找到一个例子上述情况下提供的网站。(只有1: N 和多态性关联,但没有习惯性)。我有一个类似的情况,我的代码看起来像这样:

Factory.define :user do |user|
user.name "Foo Bar"
user.after_create { |u| Factory(:company, :users => [u]) }
end


Factory.define :company do |c|
c.name "Acme"
end

在我看来,只要创建两个不同的工厂,像:

Factory.define :user, :class => User do |u|
# Just normal attributes initialization
end


Factory.define :company, :class => Company do |u|
# Just normal attributes initialization
end

当您为用户编写测试用例时,只需像这样编写即可

Factory(:user, :companies => [Factory(:company)])

希望能成功。

  factory :company_with_users, parent: :company do


ignore do
users_count 20
end


after_create do |company, evaluator|
FactoryGirl.create_list(:user, evaluator.users_count, users: [user])
end


end

警告: 将用户: [ user ]更改为: users = > [ user ] for ruby 1.8. x

这是对我有效的解决办法。

FactoryGirl.define do


factory :company do
#company attributes
end


factory :user do
companies {[FactoryGirl.create(:company)]}
#user attributes
end


end

如果您需要特定的公司,您可以使用工厂这种方式

company = FactoryGirl.create(:company, #{company attributes})
user = FactoryGirl.create(:user, :companies => [company])

Hope this will be helpful for somebody.

发现这种方式既好又冗长:

FactoryGirl.define do
factory :foo do
name "Foo"
end


factory :bar do
name "Bar"
foos { |a| [a.association(:foo)] }
end
end

Rails 5更新:

不要使用 has_and_belongs_to_many关联,应该考虑: has_many :through关联。

该关联的用户工厂如下所示:

FactoryBot.define do
factory :user do
# user attributes


factory :user_with_companies do
transient do
companies_count 10 # default number
end


after(:create) do |user, evaluator|
create_list(:companies, evaluator.companies_count, user: user)
end
end
end
end

您可以以类似的方式创建公司工厂。

一旦设置了这两个工厂,您就可以使用 companies_count option创建 user_with_companies工厂。在这里,您可以指定用户所属的公司数量: create(:user_with_companies, companies_count: 15)

你可以找到关于 工厂女工协会的详细说明。

您可以定义新的工厂,并在(: create)回调之后使用它来创建关联列表。让我们看看在这个例子中如何做到这一点:

FactoryBot.define do


# user factory without associated companies
factory :user do
# user attributes


factory :user_with_companies do
transient do
companies_count 10
end


after(:create) do |user, evaluator|
create_list(:companies, evaluator.companies_count, user: user)
end
end
end
end

Attribute company _ count 是暂时的,可以在工厂的属性中使用,也可以通过计算器在回调中使用。现在,您可以创建一个包含公司的用户,该用户可以选择指定需要多少家公司:

create(:user_with_companies).companies.length # 10
create(:user_with_companies, companies_count: 15).companies.length # 15

对于 HABTM,我使用 trait 和 callback

假设你有以下模型:

class Catalog < ApplicationRecord
has_and_belongs_to_many :courses
…
end
class Course < ApplicationRecord
…
end

你可以:

FactoryBot.define do
factory :catalog do
description "Catalog description"
…


trait :with_courses do
after :create do |catalog|
courses = FactoryBot.create_list :course, 2


catalog.courses << courses
catalog.save
end
end
end
end