FactoryGirl在Rails 4中产生验证错误

时间:2015-02-26 15:31:24

标签: ruby-on-rails ruby-on-rails-4 factory-bot

最终,我正在尝试使用FactoryGirl创建一个通过连接模型进行关联的对象实例。这是我has_many :through的标准示例。

class Partition < ActiveRecord::Base
  has_many :lists
  has_many :configs, through: :lists
end

class List < ActiveRecord::Base
  belongs_to :partition
  belongs_to :config 
end

class Config < ActiveRecord::Base
  has_many :lists
  has_many :partitions, through: :lists
end

在我的规格中,我这样做:

config = FactoryGirl.create(:config)
partition = FactoryGirl.create(:partition, configs: [config])

创建分区的行失败,Validation failed: Lists is invalid。而且我认为原因是它创造了无序的东西。这是我的验证,它指的是:

class List < ActiveRecord::Base
  validates :partition_id, presence: true, uniqueness: { scope: :config_id }
end

重要说明:这似乎在Rails 3中运行良好。我正在尝试将我们的应用程序升级到Rails 4,并且它在Rails 4中失败。

如果我将工厂更改为:

,我可以使其工作
config = FactoryGirl.create(:config)
partition = FactoryGirl.build(:partition, configs: [config])
partitions.save

然后一切似乎都很好,但那不是我想要做的。我已经读过,在我的工厂,我可以这样做:

factory :partition do |partition|  
  ...
  partition.after_create do |p|  
    p.configs << :config # Does not work, see update below
  end  
end  

但是如果可能的话,我想把我的配置传递给我的工厂,如果可能的话。

重申我的问题:如何使用FactoryGirl在Rails 4中创建一个has_many through:关系为{?1}}的对象?

更新

如果我改变我的工厂:

factory :partition do
  ...
  after(:create) do |p|
    p.build_configurations << FactoryGirl.create(:tcid)
  end
end

然后,只有当我将工厂创建改为:

时,测试才会通过
FactoryGirl.create(:partition)

但我希望的目标是:

config = # Get an instance of a Config
FactoryGirl.create(:partition, configs: [config])

更新2

似乎你 CAN 就像我想要的那样创建工厂,但我认为时机必须关闭。如果我从List删除了验证,Partition工厂在我传入configs: [config]时工作正常。

在保存配置之前,工厂似乎正在尝试保存列表(验证的位置)?想法?

2 个答案:

答案 0 :(得分:0)

我相信在您的联接表中添加inverse_of可以解决问题。像这样使用它:

class List < ActiveRecord::Base
  belongs_to :partition, inverse_of: :lists
  belongs_to :config, inverse_of: :lists
end

答案 1 :(得分:0)

会这样吗?

factory :partition do
  # partition init goes here...

  after(:create) do |partition, evaluator|
    config = create :config
    list = create :list, partition: partition, config: config
  end
end

我没有对此进行过测试,因此您必须先试一试,看看它是否适合您。这个概念首先创建配置记录,然后创建列表项。

使用评估程序,您可以允许自己传递自定义配置,而不是在Config工厂中使用默认配置,如下所示:

factory :partition do
  # partition init goes here...

  transient do
    custom_config: false
  end

  after(:create) do |partition, evaluator|
    if evaluator.custom_config
      config = custom_config
    else
      config = create :config
    end
    list = create :list, partition: partition, config: config
  end
end

这将使你能够做到这样的事情:

config = # Some custom built config
partition = FactoryGirl.create(:partition, custom_config: config)

瞬态属性非常适合创作之后,我已经使用了很多,一旦你得到它们,你会喜欢它们给你的多功能性。