如何在 Factory Girl 中创建 has_and_belongs_to_many 关联

发布于 2024-08-05 18:26:23 字数 596 浏览 7 评论 0原文

鉴于以下情况,

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

也许毫不奇怪,这会导致无限循环,因为工厂递归地相互使用彼此来定义自己。

更令人惊讶的是,我没有在任何地方找到如何做到这一点的提及,是否有定义必要工厂的模式,或者我正在做一些根本错误的事情?

Given the following

class User < ActiveRecord::Base
  has_and_belongs_to_many :companies
end

class Company < ActiveRecord::Base
  has_and_belongs_to_many :users
end

how do you define factories for companies and users including the bidirectional association? Here's my attempt

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

Perhaps unsurprisingly this results in an infinite loop as the factories recursively use each other to define themselves.

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

本宫微胖 2024-08-12 18:26:23

这是适合我的解决方案。

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

希望这对某人有帮助。

Here is the solution that works for me.

FactoryGirl.define do

  factory :company do
    #company attributes
  end

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

end

if you will need specific company you can use factory this way

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

Hope this will be helpful for somebody.

眼泪淡了忧伤 2024-08-12 18:26:23

Factorygirl 此后已进行更新,现在包含回调来解决此问题。看看 http://robots.thoughtbot.com/post /254496652/aint-no-calla-back-girl 了解更多信息。

Factorygirl has since been updated and now includes callbacks to solve this problem. Take a look at http://robots.thoughtbot.com/post/254496652/aint-no-calla-back-girl for more info.

橘味果▽酱 2024-08-12 18:26:23

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

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

希望它会起作用。

In my opinion, Just create two different factories like:

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

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

When you write the test-cases for user then just write like this

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

Hope it will work.

奶气 2024-08-12 18:26:23

我在提供的网站上找不到上述案例的示例。 (只有 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

I couldn´t find an example for the above mentioned case on the provided website. (Only 1:N and polymorphic assocations, but no habtm). I had a similar case and my code looks like this:

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
|煩躁 2024-08-12 18:26:23

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

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

company.users << user 
company.save! 

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! 
緦唸λ蓇 2024-08-12 18:26:23

发现这种方式很好而且很详细:

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

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

Found this way nice and verbose:

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

  factory :bar do
    name "Bar"
    foos { |a| [a.association(:foo)] }
  end
end
原野 2024-08-12 18:26:23
  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 => [用户] 对于 ruby​​ 1.8.x

  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

Warning: Change users: [user] to :users => [user] for ruby 1.8.x

鸵鸟症 2024-08-12 18:26:23

对于 HABTM,我使用了特征和回调

假设您有以下模型:

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

For HABTM I used traits and callbacks.

Say you have the following models:

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

You can define the Factory above:

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
总以为 2024-08-12 18:26:23

首先,我强烈鼓励您使用 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

在此之后,双方都会有 has_many 关联,并且可以按照你所做的方式在factory_girl 中分配给它们。

First of all I strongly encourage you to use has_many :through instead of habtm (more about this here), so you'll end up with something like:

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.

姐不稀罕 2024-08-12 18:26:23

Rails 5 更新:

您应该考虑:has_many :through 关联,而不是使用 has_and_belongs_to_many 关联。

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

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 选项 创建 user_with_companies 工厂。在这里您可以指定用户所属的公司数量:create(:user_with_companies,companys_count: 15)

您可以找到有关这里是工厂女孩协会

Update for Rails 5:

Instead of using has_and_belongs_to_many association, you should consider: has_many :through association.

The user factory for this association looks like this:

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

You can create the company factory in a similar way.

Once both factories are set, you can create user_with_companies factory with companies_count option. Here you can specify how many companies the user belongs to: create(:user_with_companies, companies_count: 15)

You can find detailed explanation about factory girl associations here.

未蓝澄海的烟 2024-08-12 18:26:23

您可以定义新工厂并使用 after(: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

属性companys_count是瞬态的,可在工厂的属性中以及通过评估器的回调中使用。现在,您可以创建一个包含公司的用户,并可以选择指定您想要的公司数量:

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

You can define new factory and use after(:create) callback to create a list of associations. Let's see how to do it in this example:

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 companies_count is a transient and available in attributes of the factory and in the callback via the evaluator. Now, you can create a user with companies with the option to specify how many companies you want:

create(:user_with_companies).companies.length # 10
create(:user_with_companies, companies_count: 15).companies.length # 15
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文