我有一个工厂,可以在引擎中生成具有角色的设计用户。用户模型has_many :roles through: :roles_users
。我可以让代码与 after(:create)
一起使用子句,但不与 association:
一起使用关键字。
这有效:
应用程序/模型/myengine/role.rb
module MyEngine
class User < ActiveRecord::Base
has_many :roles_users
has_many :roles, through: :roles_users
end
end
规范/工厂/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) 钩子(Hook)可能是有原因的。从用户评论来看,上述代码存在两个问题:
- 不使用集合
- 附加关联时该对象不存在
使用@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 表,这可能是由于命名空间解析造成的问题。
最佳答案
该错误是因为您将角色的单个实例传递给 roles
而不是集合。
FactoryBot无法知道您要创建多少个角色用于关联,因此无论如何都需要手动创建它们。
无需后钩的最简单解决方法可以是 roles { [ create(:role) ] }
关于ruby-on-rails - FactoryBot has_many 通过关联出现 NoMethodError 'each',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54578789/