8 ответов:
в Rails 3.1 вы можете просто
class Form < ActiveRecord::Base serialize :column, JSON endнадеюсь, что это поможет
в Rails 3.1 вы можете использовать пользовательские кодеров с
serialize.class ColorCoder # Called to deserialize data to ruby object. def load(data) end # Called to convert from ruby object to serialized data. def dump(obj) end end class Fruits < ActiveRecord::Base serialize :color, ColorCoder.new endнадеюсь, что это помогает.
ссылки:
определение
serialize: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/base.rb#L556кодер YAML по умолчанию, который поставляется с рельсами: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/coders/yaml_column.rb
и это где звоните в
loadпроисходит: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/attribute_methods/read.rb#L132
обновление
см. ответ mid с высоким рейтингом ниже для гораздо более подходящих рельсов >= 3.1 ответ. Это отличный ответ для Rails
наверное, это то, что вы ищете.
Form.find(:first).to_jsonобновление
1) Установите 'json' gem:
gem install json2) создать класс JsonWrapper
# lib/json_wrapper.rb require 'json' class JsonWrapper def initialize(attribute) @attribute = attribute.to_s end def before_save(record) record.send("#{@attribute}=", JsonWrapper.encrypt(record.send("#{@attribute}"))) end def after_save(record) record.send("#{@attribute}=", JsonWrapper.decrypt(record.send("#{@attribute}"))) end def self.encrypt(value) value.to_json end def self.decrypt(value) JSON.parse(value) rescue value end end3) Добавить модель обратных вызовов:
#app/models/user.rb class User < ActiveRecord::Base before_save JsonWrapper.new( :name ) after_save JsonWrapper.new( :name ) def after_find self.name = JsonWrapper.decrypt self.name end end4) Тест это!
User.create :name => {"a"=>"b", "c"=>["d", "e"]}PS:
это не совсем сухой, но я сделал все возможное. Если кто-то может исправить
after_findнаUserмодель, это будет здорово.
мои требования не нуждались в большом количестве повторного использования кода на этом этапе, поэтому мой дистиллированный код является вариацией приведенного выше ответа:
require "json/ext" before_save :json_serialize after_save :json_deserialize def json_serialize self.options = self.options.to_json end def json_deserialize self.options = JSON.parse(options) end def after_find json_deserialize endУра, довольно легко, в конце концов!
я написал свой собственный кодер YAML, который принимает значение по умолчанию. Вот класс:
class JSONColumn def initialize(default={}) @default = default end # this might be the database default and we should plan for empty strings or nils def load(s) s.present? ? JSON.load(s) : @default.clone end # this should only be nil or an object that serializes to JSON (like a hash or array) def dump(o) JSON.dump(o || @default) end endС
loadиdumpявляются ли методы экземпляра он требует, чтобы экземпляр был передан в качестве второго аргументаserializeв определении модели. Вот пример этого:class Person < ActiveRecord::Base validate :name, :pets, :presence => true serialize :pets, JSONColumn.new([]) endЯ попытался создать новый экземпляр, загрузить экземпляр и сбросить экземпляр в IRB, и все это, казалось, работало правильно. Я написал блоге об этом тоже.
The
serialize :attr, JSONС помощьюcomposed_ofметод работает так:composed_of :auth, :class_name => 'ActiveSupport::JSON', :mapping => %w(url to_json), :constructor => Proc.new { |url| ActiveSupport::JSON.decode(url) }где url-это атрибут для сериализации с помощью json и auth-это новый метод, доступный в вашей модели, который сохраняет свое значение в формате json в атрибуте url. (еще не полностью протестирован, но, похоже, работает)
более простое решение-использовать
composed_ofкак описано в это сообщение в блоге Михаила Рыкова. Мне нравится это решение, потому что это требует использования меньшего количества обратных вызовов.вот суть ее:
composed_of :settings, :class_name => 'Settings', :mapping => %w(settings to_json), :constructor => Settings.method(:from_json), :converter => Settings.method(:from_json) after_validation do |u| u.settings = u.settings if u.settings.dirty? # Force to serialize end
Алеран, вы использовали этот метод с рельсами 3? У меня несколько такая же проблема, и я направлялся к сериализации, когда я столкнулся с этим сообщением Михаила Рыкова, но комментировать его блог невозможно, или, по крайней мере, на этом посту. Насколько я понимаю, он говорит, что вам не нужно определять класс настроек, однако когда я пытаюсь это сделать, он продолжает говорить мне, что настройка не определена. Поэтому мне просто интересно, использовали ли вы его и что еще нужно было описать? Спасибо.
Comments