我有一个工厂,它在引擎中生成一个设计用户w/角色。用户模型has_many :roles through: :roles_users
。我可以让代码使用after(:create)
子句,但不使用association:
关键字。
这是可行的:
app/model/myengine/role.rb
module MyEngine
class User < ActiveRecord::Base
has_many :roles_users
has_many :roles, through: :roles_users
end
end
spec/factories/roles.rb
factory :role, class: "MyEngine::Role" do
type: { 'admin' }
end
factory :user, class: "MyEngine::User" do
sequence(:email) { |n| "tester_#{n}@example.com" }
password { 'xxx' }
password_confirmation { 'xxx' }
after(:create) do |user|
user.roles << FactoryBot.create(:role)
end
end
但这不会,并且在初始化时undefined method 'each' for #<MyEngine::Role:0x0...>
测试失败:
factory :user, class: "MyEngine::User" do
sequence(:email) { |n| "tester_#{n}@example.com" }
password { 'xxx'}
password_confirmation { 'xxx' }
association: :roles, factory: :role
end
更新/编辑如下:
FactoryBot文档只是出于某种原因建议使用after(:create)钩子。从用户评论来看,上面的代码有两个问题:
- 不使用集合
- 附加关联时对象不存在
使用@Vasfed的建议,可以直接使用集合而不是对象来分配角色关联:
factory :user, class: "MyEngine::User" do
sequence(:email) { |n| "tester_#{n}@example.com" }
password { 'xxx'}
password_confirmation { 'xxx' }
roles { [ create(:role) ] }
end
根据@ulferts的建议,使用new而不是create:
factory :user, class: "MyEngine::User" do
sequence(:email) { |n| "tester_#{n}@example.com" }
password { 'xxx'}
password_confirmation { 'xxx' }
roles { [ build(:role) ] }
end
两者将产生:
ActiveRecord::RecordInvalid: Validation failed: Roles users is invalid
由于模型没有验证,这似乎指向FK表中缺少记录的问题或无法找到FK表,可能是由于名称空间解析。
2条答案
按热度按时间ktecyv1j1#
该错误是因为您将角色上的单个示例传递给
roles
而不是集合。FactoryBot无法知道您想要创建多少个角色进行关联,因此无论如何都需要手动创建它们。最简单的不带后置钩子的解决方法是
roles { [ create(:role) ] }
efzxgjgh2#
我最近遇到了一个类似的问题,并能够用以下方法解决它:
用户.rb
用户角色.rb
role.rb
factories/user.rb
工厂/user_role.rb
工厂/role.rb
用户规范rb