rspec - Cómo configurar una fábrica en FactoryGirl con la asociación has_many
ruby-on-rails-3.1 has-many-through (5)
¿Alguien puede decirme si estoy haciendo la instalación de la manera incorrecta?
Tengo los siguientes modelos que tienen has_many.through asociaciones:
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
Estoy usando Rails 3.1.rc4, FactoryGirl 2.0.2, factory_girl_rails 1.1.0 y rspec. Aquí está mi comprobación de cordura rspec rspec básica para la :listing
fábrica de :listing
:
it "creates a valid listing from factory" do
Factory(:listing).should be_valid
end
Aquí está la fábrica (: listado)
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
Las :listing_feature
y :feature
tienen una configuración similar.
Si la association :features
line está comentada, todas mis pruebas pasan.
Cuando es
association :features, :factory => :feature
el mensaje de error es undefined method ''each'' for #<Feature>
que pensé que tenía sentido para mí porque porque listing.features
devuelve una matriz. Así que lo cambié a
association :features, [:factory => :feature]
y el error que obtengo ahora es ArgumentError: Not registered: features
¿No es sensato generar objetos de fábrica de esta manera, o qué me estoy perdiendo? Muchas gracias por cualquier entrada!
Alternativamente, puede usar un bloque y omitir la palabra clave de association
. Esto hace que sea posible construir objetos sin guardarlos en la base de datos (de lo contrario, una asociación has_many guardará sus registros en el archivo db, incluso si usa la función de build
lugar de create
).
FactoryGirl.define do
factory :listing_with_features, :parent => :listing do |listing|
features { build_list :feature, 3 }
end
end
Así es como configuré el mío:
# 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
Y luego en tus pruebas puedes hacer:
@preference_set = FactoryGirl.create(:preference_set_with_preferences)
Espero que ayude.
Crear este tipo de asociaciones requiere utilizar las devoluciones de llamada de FactoryGirl.
Un conjunto perfecto de ejemplos se puede encontrar aquí.
http://robots.thoughtbot.com/post/254496652/aint-no-calla-back-girl
Para llevarlo a casa a tu ejemplo.
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
Intenté algunos enfoques diferentes y este es el que mejor funcionó para mí (adaptado a su caso)
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
Puedes usar el trait
:
FactoryGirl.define do
factory :listing do
...
trait :with_features do
features { build_list :feature, 3 }
end
end
end
Con callback
, si necesita creación de DB:
...
trait :with_features do
after(:create) do |listing|
create_list(:feature, 3, listing: listing)
end
end
Use en sus especificaciones de esta manera:
let(:listing) { create(:listing, :with_features) }
Esto eliminará la duplicación en sus fábricas y será más reutilizable.
https://robots.thoughtbot.com/remove-duplication-with-factorygirls-traits