ruby-on-rails - rails 3 : Cloning already-validated object prevents clone being invalidated -- is this strange or normal?

标签 ruby-on-rails ruby unit-testing validation clone

在 Rails (3.0) 测试代码中,我克隆了一个对象,这样我就可以在不更改原始对象的情况下破坏它进行验证测试。如果我在克隆之前调用了assert(original.valid?),那么即使我将member_id 值设置为nil,克隆也会通过validates_presence_of 测试。

下面的两个测试说明了这一点。在测试一中,克隆是在验证原始(“联系人”)之前创建的。当 member_id 丢失时,克隆正确地导致验证失败。断言 C 成功。

在测试二中,克隆是在原始版本验证后创建的。即使clone.member_id设置为nil,它也通过验证。换句话说,断言 2C 失败。测试之间的唯一区别是两行的顺序:

  cloned = contact.clone
  assert(contact.valid?,"A")

这是怎么回事?这是正常的 Ruby 行为吗:我只是不明白克隆?

test "clone problem 1" do
  contact = Contact.new(:member_id => 1)
  cloned = contact.clone
  assert(contact.valid?,"A")
  cloned.member_id = nil
  assert(!cloned.valid?,"C")
end

test "clone problem 2" do
  contact = Contact.new(:member_id => 1)
  assert(contact.valid?,"2A")
  cloned = contact.clone
  cloned.member_id = nil
  assert(!cloned.valid?,"2C")
end

最佳答案

你会感到惊讶 - 它不起作用!

好的,原因可以在 Rails 代码中找到。第一次验证将运行代码:

# Validations module

# Returns the Errors object that holds all information about 
# attribute error messages.
def errors
  @errors ||= Errors.new(self)
end

由于这是第一次运行,因此它将创建 Errors 类的新实例。很简单,不是吗?但有一个问题——参数是 self。在您的情况下,它是“联系”对象。

稍后,当您在克隆对象上再次调用此方法时,将不会再次创建 @errors 实例 - 因为它不为空。就是这样!使用较旧的 self ,而不是传递“克隆” self 。

稍后在验证代码中,Errors 类运行从@base 读取值的代码,@base 是初始化时的self。你能看见它吗?测试值是从原始模型而不是克隆模型中读取的!因此,对“克隆”对象的验证基于原始值运行。

好的,到目前为止“为什么不”,现在谈谈“如何做”。

解决方案很简单 - 只需在克隆之后和验证之前将 @errors 设置为 nil 即可。由于它非常私密,简单的分配不起作用。但这是有效的:

cloned.instance_eval do
  @errors = nil
end

还有一些有趣的阅读提示:http://yehudakatz.com/2010/01/10/activemodel-make-any-ruby-object-feel-like-activerecord/

它非常全面地解释了 Rails 3 中的验证如何工作。

关于ruby-on-rails - rails 3 : Cloning already-validated object prevents clone being invalidated -- is this strange or normal?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3800129/

相关文章:

ruby - 无法将命令行参数传递给 Ruby 脚本并从命令行读取

java - 可以在 Windows 上的单元测试中运行的虚拟迷你 Linux 发行版

java - 在参数上调用方法时 PowerMockito 模拟静态方法失败

javascript - 当我在 Rails 应用程序中实现日期选择器时,为什么我的索引 View 不起作用

ruby-on-rails - ActiveRecord 加入 ID 数组

ruby-on-rails - 无法在 Mac 上安装 Redmine

ruby-on-rails - Ruby 单线故障?

arrays - 如何从数组中提取整数值(混合类型 : integers/strings) via RegExp?

ruby-on-rails - 带有 Twitter Bootstrap for Rails 表单标签的复选框

python - 在 pydev 中使用 unittest 在 Python 中对整个项目层次结构进行单元测试