我有一个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
字段的方式处理主要字段,并希望有人可以解决这些问题。
答案 0 :(得分:0)
我无法解释为什么验证以一种方式工作,而不是另一种方式。
但我认为基本上你的问题是由于serialize
仅定义了在保存时使用Yaml序列化属性并在加载时反序列化的事实。
换句话说:你做serialize :filters, Array
时唯一能说的就是那个
保存Foo时,首先使用Yaml序列化它的过滤器属性, 从DB加载Foo时,请确保该值的值 filters属性是反序列化后的数组,否则引发异常
它不会影响查询的构造方式。相反,使用Rails通常的查询规则。因此,数组将转换为逗号分隔的数字列表。例如,在构造LIKE
查询时,这是有意义的。这就是查询失败的原因。 DB字段是一个字符串,但您正在尝试将其与列表进行比较。
我没有在Rails 4中使用本机PostgreSQL数组列,但我的猜测是,如果您使用这些列而不是序列化类型解决方案,这些问题就会解决。您可以在数据库级别上搜索数组内容,从而获得额外的好处。