Создать пользователя FactoryBot с отношением has_one - PullRequest
1 голос
/ 06 марта 2019

Фон:

Я пытаюсь создать объект FactoryBot, связанный с has_one / own_to

Пользователь has_one Car

Car has_one Style

Стиль имеет атрибут {style_number: "1234"}

Вопрос

Мой контроллер ссылается на пользователя, пользователя has_one Car, Car has_one Style, и мне нужно установить эти значения в FactoryBot.

Как мне создать пользователя, у которого также есть объект Car, у которого есть объект Style?

Я читаю документацию 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

private

   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

Rspec Test

Фабрика: Пользователь

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

Тест

Пользователь должен войти в систему и User.car.style.style_number должен быть установлен в"1234"
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».

Пробная версия 1 (https://github.com/thoughtbot/factory_bot_rails/issues/232)

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

Ошибка при следе 1

SystemStackError: слишком большой уровень стека

Trail 2

Я попробовал рекомендацию srng

РЕДАКТИРОВАТЬ: для полиморфной ассоциации попробуйте;

FactoryBot.define do factory: car, класс: Car do make {"Holden "} ассоциация модели {" UTE "}: стилевое, заводское:: конец стиля

и ошибка:

ActiveRecord :: RecordInvalid: сбой проверки: должен существовать стил

Я думаю, что это проблема рельсов 5.https://github.com/rails/rails/issues/24518

Однако я хотел бы сохранить свой код с добавлением необязательного: true.Есть ли способ сделать это?

Trail 3

FactoryBot.define do
   factory :car, class: Car do
     make { "Holden" }
     model  { "UTE" }
     after(:create) do |car|
        create(:style, stylable: car)
     end
   end
 end

Вторая рекомендация Срнга, и, хотя он сработал, я получил немного другую ошибку:

ActiveRecord :: RecordInvalid: проверка не удалась: пользователь должен существовать

1 Ответ

1 голос
/ 06 марта 2019

Чтобы создать зависимые фабрики, вы должны создать фабрику для каждой модели, а затем просто добавить зависимое 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
...