我有一家工厂,可以在引擎内生成具有角色的设计用户。用户模型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表的麻烦。
答案 0 :(得分:1)
错误是因为您要将角色上的单个实例传递给roles
而不是集合。
FactoryBot无法知道要为关联创建多少个角色,因此无论如何都需要手动创建它们。
最简单的解决方法是roles { [ create(:role) ] }