FactoryBot创建Order时出现NoMethodError: undefined method `user=' 求助
问题:FactoryBot创建Order时触发NoMethodError错误
背景信息
我先整理下你提供的代码和问题场景:
1. User模型的FactoryBot工厂
FactoryBot.define do factory :user do |f| f.sequence(:first_name) { |n| "#{Faker::Name.first_name}foo#{n}" } f.sequence(:last_name) { |n| "#{Faker::Name.last_name}foo#{n}" } f.sequence(:email) { |n| "foo#{n}@example.com" } f.password "foobar" f.password_confirmation { |u| u.password } f.sequence(:confirmed_at) { Date.today } f.sequence(:telephone_number) { Faker::Number.number(10) } f.sequence(:mobile_phone_number) { Faker::Number.number(10) } f.sequence(:verification_code) { '0000' } f.sequence(:is_verified) { false } end end
2. 原Order模型的FactoryBot工厂
FactoryBot.define do factory :order do association :store association :user total_price Faker::Number.positive total_discount Faker::Number.positive end end
3. Order模型的关联定义
class Order < ApplicationRecord belongs_to :customer, class_name: 'User' belongs_to :carrier, class_name: 'User' belongs_to :store end
4. 测试数据定义(order_controllers_spec.rb)
let(:customer) { FactoryBot.create(:user) } let(:carrier) { FactoryBot.create(:user) } let(:store) { FactoryBot.create(:store) } let(:order) { FactoryBot.create(:order, customer_id: customer.id, carrier_id: carrier.id, store_id: store.id) }
5. 测试代码及错误
测试代码:
describe "GET show" do it 'has a 200 status code' do get :show, params: { id: order_item.id } expect(response.status).to eq(200) end end
触发的错误:
Failure/Error: let(:order) { FactoryBot.create(:order, customer_id: customer.id, carrier_id: carrier.id, store_id: store.id) } NoMethodError: undefined method `user=' for #<Order:0x00007fcd2efc5118>
问题根源
问题出在Order的FactoryBot工厂定义上:你的Order模型里根本没有belongs_to :user的关联,而是定义了belongs_to :customer和belongs_to :carrier(都关联到User类),但工厂里却写了association :user。FactoryBot会尝试给Order实例调用user=方法来设置这个关联,但Order模型不存在这个方法,所以直接报错了。
解决方案
步骤1:修正Order的FactoryBot工厂
把错误的association :user替换成正确的关联,同时可以给customer和carrier设置默认值(用FactoryBot自动生成),这样测试时如果需要自定义再传参数:
FactoryBot.define do factory :order do association :store # 替换原来的:user关联,改成正确的customer和carrier association :customer, factory: :user association :carrier, factory: :user total_price Faker::Number.positive total_discount Faker::Number.positive end end
步骤2:优化测试数据的定义(更规范的写法)
不需要手动传xxx_id,直接传关联对象即可,FactoryBot会自动处理id的赋值:
let(:customer) { FactoryBot.create(:user) } let(:carrier) { FactoryBot.create(:user) } let(:store) { FactoryBot.create(:store) } let(:order) { FactoryBot.create(:order, customer: customer, carrier: carrier, store: store) }
步骤3:修复测试代码里的小问题
你的GET show测试里用了order_item.id,但你定义的变量是order,这里应该改成order.id,否则会触发另一个未定义变量的错误:
describe "GET show" do it 'has a 200 status code' do get :show, params: { id: order.id } expect(response.status).to eq(200) end end
做完以上修改后,再运行测试应该就能正常通过了!
内容的提问来源于stack exchange,提问作者MEH
相关产品推荐
相关产品推荐

