3

У меня есть модель с отношением друг к другу, это опрос и выбор.Rspec, Factory Girl build with has_many

Как их правильно проверить, потому что ниже код вызывает ActiveRecord::RecordInvalid:. Я хочу создать родителя (Poll) и его детей (Choices) на ходу, вместо того чтобы создать родителя (Poll), а затем сохранить детей (Choices) после этого.

Вот коды:

Во-первых, ошибка у меня для всех тестов:

Failure/Error: @poll = FactoryGirl.build(:poll_with_choices, user: @user) 
ActiveRecord::RecordInvalid: 
    Validation failed: Choices choices required at least 2 

Опрос Модель:

class Poll < ActiveRecord::Base 
    belongs_to :user 
    has_many :choices 
    accepts_nested_attributes_for :choices 

    validates :title, presence: true 
    validates_each :choices do |record, attr, value| 
    record.errors.add attr, "choices required at least 2" if record.choices.length < 2 
    end 
end 

Poll завод:

FactoryGirl.define do 
    factory :poll do 
    title { FFaker::Lorem.phrase } 
    description { FFaker::Lorem.sentences } 
    user 

    factory :poll_with_choices do 
     transient do 
     choices_count 3 
     end 

     after(:build) do |poll, evaluator| 
     build_list(:choice, evaluator.choices_count) 
     end 
    end 
    end 
end 

Выбор завода:

FactoryGirl.define do 
    factory :choice do 
    label { FFaker::Name.name } 
    votes 0 
    poll 
    end 
end 

Опрос спецификации

require 'rails_helper' 

RSpec.describe Poll, type: :model do 
    before do 
    @user = FactoryGirl.create(:user) 
    @poll = FactoryGirl.build(:poll_with_choices, user: @user) 
    end 

    subject { @poll } 

    it { should respond_to(:title) } 
    it { should respond_to(:description) } 

    it { should validate_presence_of(:title) } 

    it { should belong_to(:user) } 
    it { should have_many(:choices) } 
    it { should accept_nested_attributes_for(:choices) } 

    describe "#save" do 
    before do 
     @user = FactoryGirl.create(:user) 
    end 

    it "success" do 
     poll = FactoryGirl.build(:poll_with_choices, user: @user) 
     expect(poll.save).to eql true 
    end 

    it "fail" do 
     poll = FactoryGirl.build(:poll, user: @user) 
     poll.choices = FactoryGirl.build_list(:choice, 1) 
     expect(poll.save).to eql false 
    end 
    end 
end 

В качестве сравнения для FactoryGirl.create, неFactoryGirl.build: http://www.rubydoc.info/gems/factory_girl/file/GETTING_STARTED.md#Associations

Спасибо, заранее.

ответ

3

Наконец я получить эту работу с FactoryGirl черты и attributes

Вот код poll фабрики:

FactoryGirl.define do 
    factory :poll do 
    title { FFaker::Lorem.phrase } 
    description { FFaker::Lorem.sentences } 
    user 
    choices_attributes { [FactoryGirl.attributes_for(:choice),  FactoryGirl.attributes_for(:choice), FactoryGirl.attributes_for(:choice)] } 

    trait :with_many_choices do 
     choices_attributes { [ 
     FactoryGirl.attributes_for(:choice), FactoryGirl.attributes_for(:choice), 
     FactoryGirl.attributes_for(:choice), FactoryGirl.attributes_for(:choice), 
     FactoryGirl.attributes_for(:choice), FactoryGirl.attributes_for(:choice) 
     ] } 
    end 

    trait :with_invalid_choices do 
     choices_attributes { [FactoryGirl.attributes_for(:choice),  FactoryGirl.attributes_for(:choice), FactoryGirl.attributes_for(:choice, label: '')] } 
    end 

    trait :with_lack_of_choices do 
     choices_attributes { [FactoryGirl.attributes_for(:choice)] } 
    end 

    trait :without_choices do 
     choices_attributes { [] } 
    end 
    end 
end 

Список литературы (спасибо):

0

Если я вижу это правильно у вас есть ошибка в вашем заводе:

FactoryGirl.define do 
    factory :poll do 
    title { FFaker::Lorem.phrase } 
    description { FFaker::Lorem.sentences } 
    user 

    factory :poll_with_choices do 
     transient do 
     choices_count 3 
     end 

     after(:build) do |poll, evaluator| 
     build_list(:choice, evaluator.choices_count, poll: poll) 
     end 
    end 
    end 
end 

вам нужно назначить свой опрос на выбор в противном случае выбора завод будет создать опрос для каждого выбора.

+0

благодарит @BooVeMan, но ничего не меняет. – ruwhan

+0

Хорошо, я вижу проблему в вашем коде.Объект опроса должен существовать, чтобы выбор мог быть добавлен (вам нужен идентификатор для ссылки на выбор), но если вы проверяете существование зависимых объектов (вариантов) до того, как родительский объект существует, вы вызываете проблемы и должны прибегайте к странному коду, как вы. вы должны пересмотреть стратегию проверки. – BooVeMan

0

Это то, что я сделал в моем случае:

FactoryBot.define do 
    factory :store do 
    sequence(:name) { |n| "Store #{n}" } 
    association :user 
    sellers_attributes [ FactoryBot.attributes_for(:seller) ] 
    end 
end 

мне пришлось реорганизовать мой тест и переименовать несколько вещей.

Смежные вопросы