我正在尝试创建一个与has_one / belongs_to相关的FactoryBot对象
用户has_one车
汽车has_one风格
样式具有属性{style_number:“ 1234”}
我的控制器引用了用户,用户has_one Car,Car has_one Style,我需要在FactoryBot中设置这些值。
如何创建同时具有Car对象和Style对象的User?
我阅读了文档https://github.com/thoughtbot/factory_bot/blob/master/GETTING_STARTED.md
但是,我不理解他们如何建议这样做,我认为我需要嵌套这三个对象,但是在语法上感到困惑。
before_action :authenticate_user!
before_action :set_steps
before_action :setup_wizard
include Wicked::Wizard
def show
@user = current_user
@form_object = form_object_model_for_step(step).new(@user)
render_wizard
end
私人
def set_steps
if style_is_1234
self.steps = car_steps.insert(1, :style_car)
else
self.steps = car_steps
end
end
def style_is_1234
if params.dig(:form_object, :style_number)
(params.dig(:form_object, :style_number) & ["1234"]).present?
else
(current_user.try(:car).try(:style).try(:style_number) & ["1234"]).present?
end
end
def car_steps
[:type,:wheel, :brand]
end
FactoryBot.define do
factory :user, class: User do
first_name { "John" }
last_name { "Doe" }
email { Faker::Internet.email }
password { "somepassword" }
password_confirmation { "some password"}
end
end
before(:each) do
@request.env["devise.mapping"] = Devise.mappings[:user]
user = FactoryBot.create(:user)
sign_in user
context "Requesting with second step CarStyle" do
it "should return success" do
get :show, params: { :id => 'car_style' }
expect(response.status).to eq 200
end
end
当前该测试失败,因为User.Car.Style.style_number未设置为“ 1234”。
FactoryBot.define do
factory :user, class: User do
first_name { "John" }
last_name { "Doe" }
email { Faker::Internet.email }
password { "somepassword" }
password_confirmation { "some password"}
car
end
end
FactoryBot.define do
factory :car, class: Car do
make { "Holden" }
model { "UTE" }
end
end
FactoryBot.define do
factory :style, class: Style do
color { "blue" }
for_car
trait :for_car do
association(:styable, factory: :car)
end
end
end
SystemStackError: 堆栈级别太深
我尝试了srng的推荐
编辑:对于多态关联,请尝试;
FactoryBot.define做 工厂:汽车,类别:汽车 使{“保持”} 型号{“ UTE”} 协会:风格,工厂:风格 结束 结束
并得到错误:
ActiveRecord :: RecordInvalid:验证失败:样式必须存在
我认为这是Rails 5问题。 https://github.com/rails/rails/issues/24518
但是,我想通过添加optional:true保留我的代码。有什么办法吗?
FactoryBot.define do
factory :car, class: Car do
make { "Holden" }
model { "UTE" }
after(:create) do |car|
create(:style, stylable: car)
end
end
end
尝试了Srng的第二条建议,尽管它对他有用,但我得到了一个略有不同的错误:
ActiveRecord :: RecordInvalid: 验证失败:用户必须存在
答案 0 :(得分:1)
要创建从属工厂,您必须为每个模型创建一个工厂,然后只需将从属Model
名称添加到您的工厂即可。
FactoryBot.define do
factory :user, class: User do
first_name { "John" }
last_name { "Doe" }
email { Faker::Internet.email }
password { "somepassword" }
password_confirmation { "some password"}
car
end
end
FactoryBot.define do
factory :car, class: Car do
make { "Holden" }
model { "UTE" }
style
end
end
FactoryBot.define do
factory :style, class: Style do
color { "blue" }
end
end
编辑: 相关代码;
# Factories
FactoryBot.define do
factory :user, class: User do
first_name { "John" }
last_name { "Doe" }
email { Faker::Internet.email }
password { "somepassword" }
password_confirmation { "some password"}
after(:create) do |user|
user.car ||= create(:car, :user => user)
end
end
end
factory :style, class: Style do
style_number { "Blue" }
end
factory :car, class: Car do
name { "Holden" }
trait :style do
association :stylable, factory: :style
end
end
#models
class Car < ApplicationRecord
has_one :style, as: :styleable
end
class Style < ApplicationRecord
belongs_to :styleable, polymorphic: true
belongs_to :car
end
# Migrations - The belongs_to is the only important one
class CreateStyles < ActiveRecord::Migration[5.2]
def change
create_table :styles do |t|
t.string :style_number
t.belongs_to :stylable, polymorphic: true
t.timestamps
end
end
end
class CreateCars < ActiveRecord::Migration[5.2]
def change
create_table :cars do |t|
t.string :name
t.timestamps
end
end
end
答案 1 :(得分:0)
在工厂中,可以使用瞬变块来实现此目的的另一种方法。 希望下面的代码片段可以帮助您以新的方式进行探索。
注意:这未经测试。
## To Create a user in test case
# create(:user) # defaults to 1234 style number
# create(:user, car_style_number: 5678)
DEFAULT_STYLE_NUMBER = 1234
FactoryBot.define do
factory :user do
transient do
car_style_number { DEFAULT_STYLE_NUMBER }
end
first_name { "John" }
last_name { "Doe" }
email { Faker::Internet.email }
after(:create) do |user, evaluator|
user.car = create(:car, car_style_number: evaluator.car_style_number, user: user)
end
end
end
FactoryBot.define do
factory :car do
transient do
car_style_number { DEFAULT_STYLE_NUMBER }
end
make { "Holden" }
model { "UTE" }
after(:create) do |car, evaluator|
car.style = create(:style, style_number: evaluator.car_style_number, car: car)
end
end
end
FactoryBot.define do
factory :style do
style_number { DEFAULT_STYLE_NUMBER }
end
end