Rails: как создать Factory с помощью FactoryGirl для отношения own_to + has_many, при котором оба конца проверяют наличие друг друга?

Я изучаю ассоциации, и у меня возникают проблемы с тестированием своих ассоциаций с помощью RSpec, shoulda-matchers и FactoryGirl.

У меня есть модель игры, экземпляры которой должны принадлежать производителю, поэтому я использую проверку присутствия.

Производители могут иметь более одной связанной с ними игры, поэтому с точки зрения производителя существует связь has_many games. Кроме того, я хочу убедиться, что производитель создается только в том случае, если он связан с игрой (посредством проверки) (я не хочу отслеживать производителей, не связанных с играми).

Вот код:

class Game < ActiveRecord::Base
    belongs_to :manufacturer
    validates :name, presence: {message: 'The game name is required'}
    validates :description, presence:  {message: 'A short game description is required'}
    validates :manufacturer, presence:  true
 end

class Manufacturer < ActiveRecord::Base
    has_many :games
    validates :name, presence: {message: 'The manufacturer name is required and must be unique'}
    validates :name, uniqueness: {message: 'A manufacturer by this name already exits.'}, if: "name.present?"
    validates :games, presence: { message: 'Every manufacturer must be associated with at least one game.' }
end

Как видите, оба они подтверждают друг друга, поэтому не будет игр без производителя и производителей без игр.

Мне сложно создать Factory с помощью FactoryGirl для создания действительного экземпляра производителя для тестирования.

Как я могу создать фабрику производителя и фабрику игр, чтобы иметь действующую фабрику, где я могу тестировать ассоциации с помощью shoulda-matchers? (БД правильно настроена со столбцами для внешних ключей и идентификаторов)

ИЗМЕНИТЬ

Я безуспешно пробовал следующее ...

ПОПРОБОВАТЬ 1

FactoryGirl.define do
    factory :game do
        name "Space Invaders"
        description "Space Invaders was one of the early blockbuster shooting games."
        release_date '1978'
        association :manufacturer, strategy: :build
      end
    end


FactoryGirl.define do
      factory :manufacturer do
        name 'Atari'
        games {create_list(:game, 1)}
      end
 end

Ошибка:

/Users/mymac/.rvm/gems/ruby-2.1.5@sr-arcade-nomad/bin/ruby_executable_hooks:15: stack level too deep (SystemStackError)

2 попытки

FactoryGirl.define do
  factory :game do
    name 'Space Invaders'
    description "Space Invaders was one of the early blockbuster shooting games."
    manufacturer 'Atari'
  end
end

FactoryGirl.define do
  factory :manufacturer do
    name 'Atari'
    games {create_list(:game, 1)}
  end
end

Ошибка:

.../gems/activerecord-4.1.1/lib/active_record/associations/association.rb:216:in `raise_on_type_mismatch!': Manufacturer(#70244044131760) expected, got String(#70244001467180) (ActiveRecord::AssociationTypeMismatch)

person Sergio Rodriguez    schedule 13.03.2015    source источник


Ответы (2)


Попробуйте следующий код:

factory :game do
  name
  description
  manufactor
end

factory :manufacturer do
  name
  games { create_list(:game, 1) }
end
person IcyBright    schedule 13.03.2015
comment
Рядом с name и description не должно быть запятых. - person Prakash Murthy; 13.03.2015
comment
Это не работает. Просто отредактировал свой вопрос, чтобы показать, что я пробовал, а что не работает. - person Sergio Rodriguez; 17.03.2015

Я ищу решение, с помощью которого я могу легко переопределить ассоциацию игр. Если в данном случае это не касается, вы можете использовать ловушку после сборки:

factory :manufacturer do
   …
   after(:build) do |m|
      m.games << build(:game, manufacturer: m)
   end
end

Проблема с переопределением "вроде как решена", если вы поместите это после (: build) в трейт, но тогда build(:manufacturer) больше не действует. Так что все еще не идеальный, но тем не менее рабочий завод.

Опять же, эта ситуация с круговой проверкой присутствия не идеальна для начала. Единственный способ сделать это в Rails (способ Rails) - использовать вложенную форму. Затем вы создадите вложенные объекты с такими параметрами, как { name: … , games_attributes: {1 => {<attributes for game 1}, …}. Вам, вероятно, тогда тоже стоит построить фабрику, как с games_attributes. Другие случаи просто невозможны:

game = Game.new …
manufacturer = Manufacturer.new …

Теперь сохраните их (вложенные) с этими проверками на месте ... сначала нужно будет пройти ...

person Ivo Dancet    schedule 26.06.2015
comment
accepts_nested_attributes_for :games тоже должен быть там, чтобы использовать games_attributes (например, games_attributes: {1 => attributes_for(:game) }) - person kangkyu; 21.02.2016