Rails验证了序列化文本数组的范围

时间:2014-02-19 05:30:42

标签: ruby-on-rails postgresql

我有一个Rails模型,它有一个字段array_field,它是一个序列化的文本数组。我希望这个数组值和another_field的值的组合是唯一的。

应该直截了当,不是吗?

class Foo < ActiveRecord::Base
  validates_uniqueness_of :array_field, scope: [:another_field]

  serialize :filters, Array
end

这不起作用。但是,如果我在验证中切换它们,

validates_uniqueness_of :another_field, scope: [:array_field]按预期工作。

有人可以解释为什么会这样吗?这是预期的行为吗?

array_field的值为nil[]时,以前设置的Postgres错误是:

PG::SyntaxError: ERROR:  syntax error at or near ")"
   LINE 1: ...other_field" = 103 AND "foo"."array_field" = ) LIMIT 1

array_field[[1, 2], [3, 4, 5]](我正在使用的样本多列表)时,它是:

PG::UndefinedFunction: ERROR:  operator does not exist: text = integer
   LINE 1: ...other_field" = 103 AND "foo"."array_field" = 1, 2, 3, 4, 5) LIMIT 1

似乎Rails不知道如何翻译此查询的序列化对象。我错过了什么或者这是一个错误吗?

编辑:这是在Rails 4.0.2中发生的。

第二次修改:

澄清:我理解为什么会发生这种情况(Rails具有列表查询的自定义逻辑),并且我在验证之前使用自定义验证器手动执行序列化,并使用自定义序列化器来避免与Yaml字符串进行比较时出现问题(详见我的另一个问题here)。

此时我大多只是想知道为什么validates_uniqueness_of以不同于scope字段的方式处理主要字段,并希望有人可以解决这些问题。

1 个答案:

答案 0 :(得分:0)

我无法解释为什么验证以一种方式工作,而不是另一种方式。

但我认为基本上你的问题是由于serialize仅定义了在保存时使用Yaml序列化属性并在加载时反序列化的事实。

换句话说:你做serialize :filters, Array时唯一能说的就是那个

  

保存Foo时,首先使用Yaml序列化它的过滤器属性,   从DB加载Foo时,请确保该值的值   filters属性是反序列化后的数组,否则引发异常

它不会影响查询的构造方式。相反,使用Rails通常的查询规则。因此,数组将转换为逗号分隔的数字列表。例如,在构造LIKE查询时,这是有意义的。这就是查询失败的原因。 DB字段是一个字符串,但您正在尝试将其与列表进行比较。

我没有在Rails 4中使用本机PostgreSQL数组列,但我的猜测是,如果您使用这些列而不是序列化类型解决方案,这些问题就会解决。您可以在数据库级别上搜索数组内容,从而获得额外的好处。