在Rails中将factory_girl与具有唯一约束的关联一起使用.得到重复的错误 [英] Using factory_girl in Rails with associations that have unique constraints. Getting duplicate errors

查看:41
本文介绍了在Rails中将factory_girl与具有唯一约束的关联一起使用.得到重复的错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在与Rails 2.2项目一起工作以对其进行更新.我正在用工厂替换现有的灯具(使用factory_girl),并且遇到了一些问题.问题在于模型代表具有查询数据的表.当我用两个具有相同产品类型的产品创建购物车时,每个创建的产品都在重新创建相同的产品类型.这是由于对ProductType模型进行的唯一验证而导致的.

I'm working with a Rails 2.2 project working to update it. I'm replacing existing fixtures with factories (using factory_girl) and have had some issues. The problem is with models that represent tables with lookup data. When I create a Cart with two products that have the same product type, each created product is re-creating the same product type. This errors from a unique validation on the ProductType model.

这是从单元测试中获得的,我在其中创建了购物车并将其分成几部分.我必须这样做才能解决问题.但这仍然说明了问题.我会解释.

This is from a unit test where I create a Cart and put it together in pieces. I had to do this to get around the problem. This still demonstrates the problem though. I'll explain.

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))]

要添加的两个产品具有相同的类型,当创建每个产品时,它会重新创建产品类型并创建重复项.

The two products being added are of the same type and when each product is created it is re-creating the product type and creating duplicates.

所生成的错误是: "ActiveRecord :: RecordInvalid:验证失败:名称已被采用,代码已被采用"

The error that gets generated is: "ActiveRecord::RecordInvalid: Validation failed: Name has already been taken, Code has already been taken"

此示例的解决方法是覆盖正在使用的产品类型,并传入一个特定的实例,因此仅使用一个实例.提前获取"add_product_type",并将其传递给每个购物车项目.

The workaround for this example is to override the product type being used and pass in a specific instance so only one instance is used. The "add_product_type" is fetched early and passed in for each cart item.

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

问题

将factory_girl与选择列表"类型的关联一起使用的最佳方法是什么?

Question

What is the best way to use factory_girl with "pick-list" types of associations?

我希望 的工厂定义包含所有内容,而不必在测试中进行组装,尽管我可以接受.

I'd like for the factory definition to contain everything instead of having to assemble it in the test, although I can live with it.

factories/product.rb

factories/product.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

ProductType的代码"的目的是使应用程序可以赋予它们特殊的含义. ProductType模型看起来像这样:

The purpose of ProductType's "code" is so the application can give special meaning to them. The ProductType model looks something like this:

class ProductType < ActiveRecord::Base
  has_many :products

  validates_presence_of :name, :code
  validates_uniqueness_of :name, :code
  #...
end

factories/cart.rb

factories/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

当我用两个具有相同产品类型的商品来定义购物车时,会出现上述相同的错误.

When I try to define the cart with two items of the same product type, I get the same error described above.

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

推荐答案

我遇到了同样的问题,并在工厂文件的顶部添加了一个lambda来实现单例模式,如果数据库已被清除,它还会重新生成模型自上一轮测试/规格以来:

I encountered the same problem and added a lambda at the top of my factories file that implements a singleton pattern, which also regenerates the model if the db has been cleared since the last round of tests/specs:

saved_single_instances = {}
#Find or create the model instance
single_instances = lambda do |factory_key|
  begin
    saved_single_instances[factory_key].reload
  rescue NoMethodError, ActiveRecord::RecordNotFound  
    #was never created (is nil) or was cleared from db
    saved_single_instances[factory_key] = Factory.create(factory_key)  #recreate
  end

  return saved_single_instances[factory_key]
end

然后,使用示例工厂,可以使用factory_girl lazy属性运行lambda

Then, using your example factories, you can use a factory_girl lazy attribute to run the lambda

Factory.define :product do |p|
  p.product_type  { single_instances[:add_product_type] }
  #...this block edited as per comment below
end

Voila!

这篇关于在Rails中将factory_girl与具有唯一约束的关联一起使用.得到重复的错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆