Как настроить factory в FactoryGirl с помощью ассоциации has_many
Может ли кто-нибудь сказать мне, если я просто неправильно настрою настройку?
У меня есть следующие модели с has_many.through ассоциациями:
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
Я использую Rails 3.1.rc4, FactoryGirl 2.0.2, factory_girl_rails 1.1.0 и rspec. Вот моя основная проверка безопасности rspec rspec для :listing
factory:
it "creates a valid listing from factory" do
Factory(:listing).should be_valid
end
Вот Factory (: listing)
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
Фабрики :listing_feature
и :feature
аналогично настроены.
Если строка association :features
закомментирована, все мои тесты пройдут.
Когда он
association :features, :factory => :feature
сообщение об ошибке
undefined method 'each' for #<Feature>
, который, как я думал, имеет смысл для меня, потому что listing.features
возвращает массив. Поэтому я изменил его на
association :features, [:factory => :feature]
и ошибка, которую я получаю сейчас, это ArgumentError: Not registered: features
Разве не разумно генерировать объекты factory таким образом, или что мне не хватает? Большое спасибо за любые и все данные!
Ответы
Ответ 1
Создание таких ассоциаций требует использования обратных вызовов 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
Ответ 2
В качестве альтернативы вы можете использовать блок и пропустить ключевое слово association
. Это позволяет создавать объекты без сохранения в базе данных (иначе ассоциация has_many сохранит ваши записи в db, даже если вы используете функцию build
вместо create
).
FactoryGirl.define do
factory :listing_with_features, :parent => :listing do |listing|
features { build_list :feature, 3 }
end
end
Ответ 3
Я пробовал несколько разных подходов, и это тот, который работал наиболее надежно для меня (адаптированный к вашему делу)
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
Ответ 4
Вы можете использовать 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
Ответ 5
Вот как я установил мой:
# 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)
Надеюсь, что это поможет.