FactoryGirl 关联模型问题:“SystemStackError:堆栈级别太深”

发布于 2024-12-05 16:40:36 字数 1585 浏览 2 评论 0原文

我正在使用 Ruby on Rails 3.0.9、RSpec-rails 2 和 FactoryGirl。我试图陈述一个工厂关联模型,但我遇到了麻烦。

我有一个如下所示的 factories/user.rb 文件:

FactoryGirl.define do
  factory :user, :class => User do
    attribute_1
    attribute_2
    ...

    association :account, :factory => :users_account, :method => :build, :email => '[email protected]'
  end
end

和一个如下所示的 factories/users/account.rb 文件:

FactoryGirl.define do
  factory :users_account, :class => Users::Account do
    sequence(:email) {|n| "foo#{n}@bar.com" }
    ...
  end
end

上面的示例按我的规范中的预期工作文件,但 iffactory :users_account 语句中添加 association :user 代码,以便

FactoryGirl.define do
  factory :users_account, :class => Users::Account do
    sequence(:email) {|n| "foo#{n}@bar.com" }
    ...
    association      :user
  end
end

收到以下错误:

Failure/Error: Unable to find matching line from backtrace
SystemStackError:
  stack level too deep

我怎样才能解决这个问题从双方\工厂访问关联模型(也就是说,在我的规范文件中,我想使用 RoR 关联模型方法,例如 user.accountaccount.user)?

PS:我读了工厂女孩和 has_one 问题和我的情况非常接近链接问题中解释的案例。也就是说,我也有一个 has_one 关联(在 UserUsers::Account 类之间)。

I am using Ruby on Rails 3.0.9, RSpec-rails 2 and FactoryGirl. I am trying to state a Factory association model but I am in trouble.

I have a factories/user.rb file like the following:

FactoryGirl.define do
  factory :user, :class => User do
    attribute_1
    attribute_2
    ...

    association :account, :factory => :users_account, :method => :build, :email => '[email protected]'
  end
end

and a factories/users/account.rb file like the following:

FactoryGirl.define do
  factory :users_account, :class => Users::Account do
    sequence(:email) {|n| "foo#{n}@bar.com" }
    ...
  end
end

The above example works as expected in my spec files, but if in the factory :users_account statement I add the association :user code so to have

FactoryGirl.define do
  factory :users_account, :class => Users::Account do
    sequence(:email) {|n| "foo#{n}@bar.com" }
    ...
    association      :user
  end
end

I get the following error:

Failure/Error: Unable to find matching line from backtrace
SystemStackError:
  stack level too deep

How can I solve that problem so to access associated models from both sides\factories (that is, in my spec files I would like to use RoR association model methods like user.account and account.user)?

P.S.: I read the Factory Girl and has_one question and my case is very close to the case explained in the linked question. That is, I have an has_one association too (between User and Users::Account classes).

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

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

发布评论

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

评论(2

じее 2024-12-12 16:40:36

根据文档,您不能将关联的双方都放入工厂。您需要使用它们的 after 回调来设置要返回的对象。

例如,在 factories/users/account.rb 文件中,您放置了类似

after(:build) do |user_account, evaluator|
    user_account.user = FactoryGirl.build(:user, :account=>user_account)
end

For has_many 关联的内容,您需要使用它们的 *_list 函数。

after(:build) do |user_account, evaluator|
    user_account.users = FactoryGirl.build_list(:user, 5, :account=>user_account)
end

注意:我认为文档中的示例有点误导,它没有向对象分配任何内容。我相信它应该是类似的(注意作业)。

# the after(:create) yields two values; the user instance itself and the
# evaluator, which stores all values from the factory, including ignored
# attributes; `create_list`'s second argument is the number of records
# to create and we make sure the user is associated properly to the post
after(:create) do |user, evaluator|
  user.posts = FactoryGirl.create_list(:post, evaluator.posts_count, user: user)
end

According to the docs, you can't just put both sides of the associations into the factories. You'll need to use their after callback to set an object(s) to return.

For instance, in the factories/users/account.rb file, you put something like

after(:build) do |user_account, evaluator|
    user_account.user = FactoryGirl.build(:user, :account=>user_account)
end

For has_many associations, you'll need to use their *_list functions.

after(:build) do |user_account, evaluator|
    user_account.users = FactoryGirl.build_list(:user, 5, :account=>user_account)
end

Note: I believe the example in the docs is a bit misleading it doesn't assign anything to the object. I believe it should be something like (note the assignment).

# the after(:create) yields two values; the user instance itself and the
# evaluator, which stores all values from the factory, including ignored
# attributes; `create_list`'s second argument is the number of records
# to create and we make sure the user is associated properly to the post
after(:create) do |user, evaluator|
  user.posts = FactoryGirl.create_list(:post, evaluator.posts_count, user: user)
end
抱着落日 2024-12-12 16:40:36

Spyle 的出色答案(仍然适用于 Rails 5.2 和 RSpec 3.8)将适用于大多数协会。我有一个用例,其中工厂需要为单个 has_many 关联(即范围类型方法)使用 2 个不同的工厂(或不同的特征)。

我最终得出的结论是:

# To build user with posts of category == 'Special' and category == 'Regular'
after(:create) do |user, evaluator|
  array = []
  array.push(FactoryBot.create_list(:post, 1, category: 'Regular')
  array.push(FactoryBot.create_list(:post, 1, category: 'Special')
  user.posts = array.flatten
end

这允许用户拥有 1 个“常规”类别的帖子和 1 个“特殊”类别的帖子。

Spyle's excellent answer (still working with Rails 5.2 and RSpec 3.8) will work for most associations. I had a use case where a factory needed to use 2 different factories (or different traits) for a single has_many association (ie. for a scope type method).

What I ended up coming up with was:

# To build user with posts of category == 'Special' and category == 'Regular'
after(:create) do |user, evaluator|
  array = []
  array.push(FactoryBot.create_list(:post, 1, category: 'Regular')
  array.push(FactoryBot.create_list(:post, 1, category: 'Special')
  user.posts = array.flatten
end

This allowed the user to have 1 post of category 'Regular' and 1 post of category 'Special.'

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