Скука и рутина это зло

run{}

ActiveRecord Store в Rails 3.2

Недавно довелось пользоваться 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].

Не самое элегантное решение, но проблему решает.

Comments