FactoryBot创建多User工厂报错:undefined method `name=' 求助
我来帮你梳理下问题的根源和解决方案:
错误原因分析
你遇到的 NoMethodError: undefined method 'name=' 有两个核心原因:
trait调用方式错误
你定义的:unencrypted_user_details是一个trait(特质),它是依附于基础:user工厂的,不能直接作为独立工厂调用。当你执行FactoryBot.create(:unencrypted_user_details)时,FactoryBot会尝试寻找名为:unencrypted_user_details的独立工厂,找不到时可能触发意外的属性赋值错误(结合第二个问题就出现了name=的报错)。字段赋值笔误
你的User模型只有username字段,但错误提示显示代码在尝试给name字段赋值。大概率是你在FactoryBot代码中不小心把username写成了name—— 比如如果代码里是name Faker::Name.name而不是username Faker::Name.name,就会直接触发这个错误,因为User模型没有name属性的setter方法。
多工厂变体的创建方式是否正确?
你用trait来定义不同属性变体的思路是完全可行且推荐的,trait非常适合复用不同的属性组合,减少重复代码。不过你也可以选择创建独立的工厂变体,两种方式各有优劣,下面给出修正后的代码示例:
方式一:优化后的trait写法(推荐)
FactoryBot.define do factory :user do # 可以在这里定义基础默认属性(比如默认用明文) # email { Faker::Internet.email } # password { "password" } # password_confirmation { "password" } # username { Faker::Name.name } trait :encrypted do email { AESCrypt.encrypt(Faker::Internet.email, ENV["AES_KEY"]) } password { AESCrypt.encrypt("password", ENV["AES_KEY"]) } password_confirmation { AESCrypt.encrypt("password", ENV["AES_KEY"]) } username { Faker::Name.name } end trait :unencrypted do email { Faker::Internet.email } password { "password" } password_confirmation { "password" } username { Faker::Name.name } end end end
正确调用方式:
# 创建加密用户 encrypted_user = FactoryBot.create(:user, :encrypted) # 创建明文用户 unencrypted_user = FactoryBot.create(:user, :unencrypted)
方式二:独立工厂变体写法
如果你更习惯直接调用独立的工厂名称,可以这样写:
FactoryBot.define do factory :user do # 基础工厂,默认生成明文用户 email { Faker::Internet.email } password { "password" } password_confirmation { "password" } username { Faker::Name.name } # 继承基础工厂的加密变体 factory :encrypted_user do email { AESCrypt.encrypt(Faker::Internet.email, ENV["AES_KEY"]) } password { AESCrypt.encrypt("password", ENV["AES_KEY"]) } password_confirmation { AESCrypt.encrypt("password", ENV["AES_KEY"]) } end end end
正确调用方式:
# 创建默认明文用户 user = FactoryBot.create(:user) # 创建加密用户 encrypted_user = FactoryBot.create(:encrypted_user)
总结
先修正你的字段赋值笔误(确保是username而非name),再调整trait的调用方式,你的工厂代码就能正常运行了。
内容的提问来源于stack exchange,提问作者Rohan

