Je travaille sur un projet Rails 2.2 pour le mettre à jour. Je remplace les fixtures existantes par des factories (en utilisant factory_girl) et j'ai rencontré quelques problèmes. Le problème concerne les modèles qui représentent des tables avec des données de consultation. Lorsque je crée un panier avec deux produits qui ont le même type de produit, chaque produit créé recrée le même type de produit. Cette erreur provient d'une validation unique sur le modèle ProductType.
Démonstration du problème
Ceci provient d'un test unitaire où je crée un panier et l'assemble par morceaux. J'ai dû faire cela pour contourner le problème. Cela démontre quand même le problème. Je vais vous expliquer.
cart = Factory(:cart)
cart.cart_items = [Factory(:cart_item,
:cart => cart,
:product => Factory(:added_users_product)),
Factory(:cart_item,
:cart => cart,
:product => Factory(:added_profiles_product))]
Les deux produits ajoutés sont du même type et lorsque chaque produit est créé, il recrée le type de produit et crée des doublons.
L'erreur qui est générée est : "ActiveRecord::RecordInvalid : Validation failed : Le nom a déjà été pris, le code a déjà été pris".
Solution de rechange
La solution de contournement pour cet exemple consiste à remplacer le type de produit utilisé et à transmettre une instance spécifique afin qu'une seule instance soit utilisée. Le "add_product_type" est récupéré au début et transmis pour chaque article du panier.
cart = Factory(:cart)
prod_type = Factory(:add_product_type) #New
cart.cart_items = [Factory(:cart_item,
:cart => cart,
:product => Factory(:added_users_product,
:product_type => prod_type)), #New
Factory(:cart_item,
:cart => cart,
:product => Factory(:added_profiles_product,
:product_type => prod_type))] #New
Question
Quelle est la meilleure façon d'utiliser factory_girl avec des associations de type "liste de sélection" ?
Je comme pour que la définition de l'usine contienne tout au lieu de devoir l'assembler dans le test, bien que je puisse vivre avec.
Contexte et détails supplémentaires
usines/produit.rb
# Declare ProductTypes
Factory.define :product_type do |t|
t.name "None"
t.code "none"
end
Factory.define :sub_product_type, :parent => :product_type do |t|
t.name "Subscription"
t.code "sub"
end
Factory.define :add_product_type, :parent => :product_type do |t|
t.name "Additions"
t.code "add"
end
# Declare Products
Factory.define :product do |p|
p.association :product_type, :factory => :add_product_type
#...
end
Factory.define :added_profiles_product, :parent => :product do |p|
p.association :product_type, :factory => :add_product_type
#...
end
Factory.define :added_users_product, :parent => :product do |p|
p.association :product_type, :factory => :add_product_type
#...
end
Le "code" de ProductType a pour but de permettre à l'application de leur donner une signification particulière. Le modèle ProductType ressemble à quelque chose comme ceci :
class ProductType < ActiveRecord::Base
has_many :products
validates_presence_of :name, :code
validates_uniqueness_of :name, :code
#...
end
usines/cart.rb
# Define Cart Items
Factory.define :cart_item do |i|
i.association :cart
i.association :product, :factory => :test_product
i.quantity 1
end
Factory.define :cart_item_sub, :parent => :cart_item do |i|
i.association :product, :factory => :year_sub_product
end
Factory.define :cart_item_add_profiles, :parent => :cart_item do |i|
i.association :product, :factory => :add_profiles_product
end
# Define Carts
# Define a basic cart class. No cart_items as it creates dups with lookup types.
Factory.define :cart do |c|
c.association :account, :factory => :trial_account
end
Factory.define :cart_with_two_different_items, :parent => :cart do |o|
o.after_build do |cart|
cart.cart_items = [Factory(:cart_item,
:cart => cart,
:product => Factory(:year_sub_product)),
Factory(:cart_item,
:cart => cart,
:product => Factory(:added_profiles_product))]
end
end
Lorsque j'essaie de définir le panier avec deux articles du même type de produit, j'obtiens la même erreur que celle décrite ci-dessus.
Factory.define :cart_with_two_add_items, :parent => :cart do |o|
o.after_build do |cart|
cart.cart_items = [Factory(:cart_item,
:cart => cart,
:product => Factory(:added_users_product)),
Factory(:cart_item,
:cart => cart,
:product => Factory(:added_profiles_product))]
end
end