113

创建has_and_belongs_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 

现在我尝试

Factory :user 

也许并不奇怪,这导致一个无限循环为一体的工厂递归使用对方来定义自己。

更令人惊讶的是,我还没有发现如何在任何地方做到这一点,有没有一种模式来定义必要的工厂,或者我正在做一些根本性的错误?

回答

40

Factorygirl已经更新,现在包括回调来解决这个问题。请参阅http://robots.thoughtbot.com/post/254496652/aint-no-calla-back-girl了解更多信息。

+36

该链接实际上没有说如何处理has_and_belongs_to_many ...我看不到如何做到这一点...... – dmonopoly 2011-07-25 21:16:45

+3

回调语法现在已经改为:'after(:create)'而不是'after_create'在工厂中女孩在这里提到:http://stackoverflow.com/questions/15003968/undefined-method-after-create-with-factorygirl – 2014-03-05 07:12:28

0

首先,我强烈建议您使用的has_many:通过替代的habtm(更多关于这here),所以你会喜欢的东西最终会:

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 

此之后,你就必须的has_many并且可以按照你做的方式在factory_girl中分配给他们。

+3

不应该是'Employment belongs_to:user'和'Employment belongs_to:company'这个连接模式将一个公司与一个用户连接起来吗? – 2010-06-15 11:00:31

+5

我通过快速浏览你提到的帖子得出的结论是,它取决于你的用例是否选择habtm或has_many:through。没有真正的“胜利者”。 – auralbee 2011-03-03 17:02:30

+0

那么,使用hmt时唯一的开销就是你必须在直通表上定义id。现在,我无法想象一个可能导致任何问题的情况。我没有说habtm是没有用的,只是在99%的用例中,使用hmt更有意义(因为它的优点)。 – 2011-03-08 21:49:40

5

对我来说有效的是在使用工厂时设置关联。 使用你的例子:

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

company.users << user 
company.save! 
9

我couldn't找到所提供的网站上的上述情况的一个例子。 (只有1:N和多态协会,但没有habtm)。我也有类似的情况,我的代码如下所示:

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 
+3

如果验证非零用户数呢? – dfens 2011-06-07 14:27:23

22

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

 
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)]) 

希望它会工作。

+2

谢谢这是我能够工作的唯一例子。工厂女孩是habtm的大头痛。 – jspooner 2011-08-01 23:55:47

+0

这不再适用于最近版本的FactoryGirl(我在想Rails 3) – Raf 2012-11-08 14:59:11

3
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 

警告:更改用户:[用户]到:用户=> [用户]对Ruby 1.8.x的

+3

不应该是: 'after_create {| company,evaluator | FactoryGirl.create_list(:user,evaluator.users_count,companies:[company]) }' ? – Raf 2012-11-08 14:56:06

120

这里是为我工作的解决方案。

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]) 

希望这将是为某人有帮助。

+4

谢谢你,最整齐的解决方案。 – 2012-05-29 19:14:56

+0

谢谢。经过数小时的沮丧,这已经解决了我的问题。 – 2012-10-08 17:26:01

+0

这只适用于所有工厂都在*一个文件*的情况,这是非常不可取的。因此下面@opsb提到的解决方案似乎更好。 – spier 2013-08-02 09:36:02

1

找到这样好的和冗长:

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

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

更新为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)

您可以找到有关factory girl associations here的详细说明。