创建 FactoryGirl 对象时绕过 Rails 验证

发布于 2024-12-08 07:32:41 字数 1005 浏览 1 评论 0原文

我有两个模型(ModelA 和 ModelB),每个模型都有 FactoryGirl 工厂。我希望 ModelB 的工厂能够 (A) 创建测试数据,并 (B) 构建(不保存到数据库)示例数据以向客户显示。由于模型中的 Rails 验证,我无法让 (A) 正常工作。

ModelA:

class ModelA < ActiveRecord::Base
  belongs_to :model_b
  validates_presence_of :model_b
end

ModelA 的工厂:

FactoryGirl.define do
  factory :model_a do
    some_attr "hello"
    model_b { FactoryGirl.build :model_b }
  end
end

ModelB 的ModelB

class ModelB < ActiveRecord::Base
  has_one :model_a
end

工厂

FactoryGirl.define do
  factory :model_b do
    some_attr "goodbye"
  end
end

我无法在不收到验证错误的情况下从这些工厂创建对象:

 ruby> FactoryGirl.create :model_a
 ActiveRecord::RecordInvalid: Validation failed: ModelB can't be blank

看来 FactoryGirl 正在尝试在保存其关联之前保存工厂对象。我意识到我可以让 ModelB 的工厂创建其关联的 ModelA(而不是构建它) - 但是,然后我将失去能够使用 ModelA 工厂构建示例数据或保存测试数据的灵活性。或者,我可以删除验证;但那样我就不会得到验证。

还有其他选择吗?

I have two models (ModelA and ModelB), and FactoryGirl factories for each. I want the factory for ModelB to be able to (A) create test data, and to (B) build (without saving to database) sample data for display to customers. I am having trouble getting (A) to work due to Rails validations in my models.

ModelA:

class ModelA < ActiveRecord::Base
  belongs_to :model_b
  validates_presence_of :model_b
end

Factory for ModelA:

FactoryGirl.define do
  factory :model_a do
    some_attr "hello"
    model_b { FactoryGirl.build :model_b }
  end
end

ModelB

class ModelB < ActiveRecord::Base
  has_one :model_a
end

Factory for ModelB

FactoryGirl.define do
  factory :model_b do
    some_attr "goodbye"
  end
end

I can't create objects from these factories without getting validation errors:

 ruby> FactoryGirl.create :model_a
 ActiveRecord::RecordInvalid: Validation failed: ModelB can't be blank

It appears that FactoryGirl is attempting to save the factory object before saving its assocations. I realize that I could have the factory for ModelB create its associated ModelA (rather than build it) - however, then I would lose the flexibility of being able to use the ModelA factory to either build sample data or save test data. Alternately, I could remove the validations; but then I wouldn't have validations.

Any other options?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

懷念過去 2024-12-15 07:32:41

这个怎么样?

FactoryGirl.build(:model_a).save(validate: false)

编辑:正如下面的 Scott McMillin 评论,如果您希望构建的对象作为变量,您可以这样做:

model_a = FactoryGirl.build(:model_a)
model_a.save(validate: false)

How about this?

FactoryGirl.build(:model_a).save(validate: false)

EDIT: As Scott McMillin comments below, if you want the built object as a variable, you can to do this:

model_a = FactoryGirl.build(:model_a)
model_a.save(validate: false)
嘿看小鸭子会跑 2024-12-15 07:32:41

我研究了几个解决方案。

一种是创建自定义代理,如下所示:
http://codetunes.com/2009/11/05/fixtures-without- validation-with-factory-girl

另一种是在工厂中设置一个 to_create 块:

FactoryGirl.define do
  factory :model_a do
     model_b { FactoryGirl.build :model_b }       

     to_create do |instance|
       instance.model_b.save!
       instance.save!
     end 
  end
end

I looked into a couple solutions.

One is to create a custom proxy, illustrated here:
http://codetunes.com/2009/11/05/fixtures-without-validation-with-factory-girl

The other is to set a to_create block in the factory:

FactoryGirl.define do
  factory :model_a do
     model_b { FactoryGirl.build :model_b }       

     to_create do |instance|
       instance.model_b.save!
       instance.save!
     end 
  end
end
窗影残 2024-12-15 07:32:41

这种循环验证不是一个好主意。您打算如何在数据库中构建真实对象?恕我直言,这根本不可能。

您需要先将对象保存到数据库中,ID 由数据库分配,只有在构建/保存对象后才能使用外键中的 ID 引用该对象。因此,为了能够引用数据库中的记录,必须首先保存它。但是,如果验证要求 ID 在保存之前已知并存在...

belongs_to 关系中,外键位于表中,然后您可以表达需要存在该键。对于 has_one 关系,外键位于另一个表中,并且您无法表达该元素应该存在的验证。因此,您应该从 ModelB 中删除验证。

希望这有帮助。

[更新]

您是否尝试编写:

FactoryGirl.define do
  factory :model_a do
    some_attr "hello"
    model_b
  end
end

This circular validation is not a good idea. How are you intending to build real objects in the database? Imho that is simply impossible.

You need to save objects to the database first, the ID is assigned by the database and only after building/saving the object can you refer to the object using the ID in a foreign-key. So in order to be able to refer to an record in the database, it has to be saved first. But if the validations require the ID's to be known and present before saving ...

In a belongs_to relation, the foreign key is in the table, and then you can express the need for the key to be present. With the has_one relationship, the foreign-key is in the other table, and you can't express the validation that the element should be present. So you should remove the validation from ModelB.

Hope this helps.

[UPDATE]

Did you try writing:

FactoryGirl.define do
  factory :model_a do
    some_attr "hello"
    model_b
  end
end
抱猫软卧 2024-12-15 07:32:41

我也遇到了同样的问题,当关联无法保存时,模型也无法保存。

也许试试这个:https://github.com/thoughtbot/factory_girl/issues/369

I encountered the same issue as well, that the model fails to save when it's associations failed to save.

Perhaps try this: https://github.com/thoughtbot/factory_girl/issues/369?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文