我正在使用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 => 'foo@bar.com'
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
上面的示例在我的spec文件中按预期工作,但{em> if 在factory :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
如何解决这个问题,以便从双方\株> 访问相关模型(也就是说,在我的spec文件中,我想使用像user.account
这样的RoR关联模型方法account.user
)的吗
P.S。:我读了Factory Girl and has_one个问题,我的案子与链接问题中解释的案例非常接近。也就是说,我也有一个has_one
关联(在User
和Users::Account
类之间)。
答案 0 :(得分:18)
根据the docs,你不能只将协会的双方都放入工厂。你需要使用他们的after回调来设置一个或多个返回的对象。
例如,在factories/users/account.rb
文件中,您添加了类似
after(:build) do |user_account, evaluator|
user_account.user = FactoryGirl.build(:user, :account=>user_account)
end
对于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
答案 1 :(得分:0)
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个类别为“特殊”的帖子。