Недавно довелось пользоваться store
-атрибутами которые появились в последних
рельсах. На самом деле store
-атрибуты довольно простая вещь: это поле в
таблице типа text
, которое хранит сложные данные сериализованные в текстовом формате.
Подобное может быть очень полезно для множества различных настроек, для которых
не хочется создавать по отдельному столбцу в таблице.
Т.к. это просто кусок сериализованных данных, то никакого индексирования и поиска по полям само-собой нет. (В отличие от документно-ориентированной MongoDB)
Вроде бы ничего особенного, главная фича в том, что с полями хранимыми с помощью
store
можно работать также как с обычными полями: использовать в формах,
проводить валидацию. Примеры использования можно увидеть
здесь,
здесь и
здесь.
Мне понадобилось реализовать хранение расписания в таблице, просто набор
промежутков времени для каждого дня. Не хотелось создавать отдельную таблицу
для промежутков, гораздо проще было бы просто сериализовать через store
.
Однако вылезла следующая проблема: непонятно как работать с этими данными на
клиентской стороне, через формы. Значения store
-полей выводились как есть,
используя ruby-синтаксис, тогда как мне нужен был JSON.
К примеру
class Activity < ActiveRecord::Base store :schedule, accessors: [:monday] end
и если присвоить полю monday
значение [{:start => "01:00am", :end => "02:00am"}]
и вывести в форме через <%= f.input :monday %>
то значение будет обычная
строка [{:start => "01:00am", :end => "02:00am"}]
, тогда как мне нужны данные
в формате JSON для более удобной работы через JavaScript.
Сделал небольшой хак, позволяющий присваивать и получать JSON.
class Activity < ActiveRecord::Base store :schedule def schedule map = self[:schedule].map { |day, value| [day, JSON(value)] } Hash[map] end [:monday].each do |day| define_method(:"#{day}=") do |value| value = value.to_json unless value.kind_of? String self[:schedule][day] = value end define_method(day) do self[:schedule][day] end end
Теперь можно получать и присваивать JSON через обычные accessors, а к объектам
обращаться с помощью .schedule[:monday]
.
Не самое элегантное решение, но проблему решает.