Как настроить фабрику в FactoryGirl с имеет много ассоциации
может кто-нибудь сказать мне, если я просто иду о настройке не так?
у меня есть следующие модели, которые имеют типа has_many.через ассоциации:
class Listing < ActiveRecord::Base
attr_accessible ...
has_many :listing_features
has_many :features, :through => :listing_features
validates_presence_of ...
...
end
class Feature < ActiveRecord::Base
attr_accessible ...
validates_presence_of ...
validates_uniqueness_of ...
has_many :listing_features
has_many :listings, :through => :listing_features
end
class ListingFeature < ActiveRecord::Base
attr_accessible :feature_id, :listing_id
belongs_to :feature
belongs_to :listing
end
я использую рельсы 3.1.rc4, FactoryGirl 2.0.2, factory_girl_rails 1.1.0 и rspec. Вот мой основной для RSpec для RSpec тест для :listing
фабрика:
it "creates a valid listing from factory" do
Factory(:listing).should be_valid
end
вот завод (: листинг)
FactoryGirl.define do
factory :listing do
headline 'headline'
home_desc 'this is the home description'
association :user, :factory => :user
association :layout, :factory => :layout
association :features, :factory => :feature
end
end
The :listing_feature
и :feature
заводы точно так же установка.
Если association :features
строка закомментирована, то все мои тесты проходят.
Когда это
association :features, :factory => :feature
сообщение об ошибке
undefined method 'each' for #<Feature>
который я думал, что имеет смысл для меня, потому что, потому что listing.features
возвращает массив. Поэтому я изменил его на
association :features, [:factory => :feature]
и ошибка, которую я получаю сейчас ArgumentError: Not registered: features
просто неразумно генерировать заводские объекты таким образом, или что я упускаю? Большое спасибо за любой и все входные данные!
5 ответов:
создание таких ассоциаций требует использования обратных вызовов FactoryGirl.
идеальный набор примеров можно найти здесь.
http://robots.thoughtbot.com/post/254496652/aint-no-calla-back-girl
чтобы привести его домой к вашему примеру.
Factory.define :listing_with_features, :parent => :listing do |listing| listing.after_create { |l| Factory(:feature, :listing => l) } #or some for loop to generate X features end
кроме того, вы можете использовать блок и пропустить
association
ключевое слово. Это позволяет создавать объекты без сохранения в базе данных (в противном случае ассоциация has_many сохранит ваши записи в БД, даже если вы используете
я попробовал несколько разных подходов, и это тот, который работал наиболее надежно для меня (адаптирован к вашему случаю)
FactoryGirl.define do factory :user do # some details end factory :layout do # some details end factory :feature do # some details end factory :listing do headline 'headline' home_desc 'this is the home description' association :user, factory: :user association :layout, factory: :layout after(:create) do |liztng| FactoryGirl.create_list(:feature, 1, listing: liztng) end end end
вы могли бы использовать
trait
:FactoryGirl.define do factory :listing do ... trait :with_features do features { build_list :feature, 3 } end end end
С
callback
, если вам нужно создание БД:... trait :with_features do after(:create) do |listing| create_list(:feature, 3, listing: listing) end end
используйте в своих спецификациях следующим образом:
let(:listing) { create(:listing, :with_features) }
это удалит дублирование на ваших заводах и будет более многоразовым.
https://robots.thoughtbot.com/remove-duplication-with-factorygirls-traits
вот как я настроил свой:
# Model 1 PreferenceSet class PreferenceSet < ActiveRecord::Base belongs_to :user has_many :preferences, dependent: :destroy end #Model 2 Preference class Preference < ActiveRecord::Base belongs_to :preference_set end # factories/preference_set.rb FactoryGirl.define do factory :preference_set do user factory: :user filter_name "market, filter_structure" factory :preference_set_with_preferences do after(:create) do |preference| create(:preference, preference_set: preference) create(:filter_structure_preference, preference_set: preference) end end end end # factories/preference.rb FactoryGirl.define do factory :preference do |p| filter_name "market" filter_value "12" end factory :filter_structure_preference, parent: :preference do filter_name "structure" filter_value "7" end end
и тогда в ваших тестах вы можете сделать:
@preference_set = FactoryGirl.create(:preference_set_with_preferences)
надеюсь, что это поможет.