2014-02-19 2 views
0

У меня есть модель 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] работает должным образом.

Может кто-нибудь объяснить, почему это так? Это ожидаемое поведение?

Ошибка Postgres для прежней установки, когда значение array_field «s является nil или [] это:

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]] (образец multiarray я использовал), это:

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 имеет собственную логику для списка запросов), и я использую как пользовательский валидатор, чтобы вручную выполнить сериализацию, прежде чем проверка и обычай сериализатор, чтобы избежать проблем со сравнением строк Ямла (как подробно описано в моем другом вопросе here).

На данный момент я в основном просто удивляюсь, почему validates_uniqueness_of обрабатывает основное поле, отличное от полей scope, и я надеюсь, что кто-то может пролить некоторый свет.

+0

Вы можете указать рельсы версии? –

+0

Rails 4.0.2, извините. – JacobEvelyn

ответ

0

Я не могу объяснить, почему валидации работают в одном направлении, но не в другом.

Но я думаю, что в основном ваши проблемы связаны с тем, что serialize определяет, что атрибут должен быть сериализован с использованием Yaml при сохранении и десериализации при загрузке.

Другими словами: единственное, что вы говорите, делая serialize :filters, Array, что

when saving a Foo, serialize it's filters attribute using Yaml first, when loading a Foo from the DB, make sure that the value of the filters attribute is an Array after deserialization, otherwise raise an exception

Это не влияет на запросы строятся. Вместо этого используются обычные правила Rails для запросов. Таким образом, массив преобразуется в список чисел, разделенный запятыми. Это имеет смысл, например, при построении запроса LIKE. Именно по этой причине запрос завершился неудачно. Поле БД представляет собой строку, но вы пытаетесь сравнить ее со списком.

Я не использовал собственные столбцы массива PostgreSQL с Rails 4, но я предполагаю, что эти проблемы будут решены, если вы использовали их вместо решения типа сериализации. Вы получаете дополнительное преимущество от поиска в содержимом массивов на уровне БД.

+0

Не вариант: 'PG :: InvalidTextRepresentation: ERROR: многомерные массивы должны иметь выражения массива с соответствующими размерами. – JacobEvelyn

+0

Пожалуйста, объясните, что вы имеете в виду. Что именно вы делали, когда получили это сообщение об ошибке? – Jesper

+0

Извините, что не ясны. Я не могу использовать собственные массивы Postgres, потому что Postgres требует, чтобы его многомерные массивы были «прямоугольными», где мои не являются (см. Образец массива в моем исходном вопросе). – JacobEvelyn

Смежные вопросы