我有一个使用序列化列的模型:
class Form < ActiveRecord::Base
serialize :options, Hash
end
有没有办法让这个序列化使用 JSON 而不是 YAML?
我有一个使用序列化列的模型:
class Form < ActiveRecord::Base
serialize :options, Hash
end
有没有办法让这个序列化使用 JSON 而不是 YAML?
在 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
Rails 附带的默认 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 的高评价答案以获得更合适的 Rails >= 3.1 答案。对于 Rails < 3.1,这是一个很好的答案。
可能这就是你要找的。
Form.find(:first).to_json
更新
1)安装' json'gem:
gem install json
2) 创建 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
end
3)添加模型回调:
#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
end
4)测试它!
User.create :name => {"a"=>"b", "c"=>["d", "e"]}
它不是很干,但我尽力了。如果有人可以修复模型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
干杯,最后很容易!
serialize :attr, JSON
using方法的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 属性中。(尚未完全测试,但似乎正在工作)
我编写了自己的 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 中,这一切似乎都正常工作。我也写了一篇关于它的博客文章。
一个更简单的解决方案是按照Michael Rykov 的这篇博客文章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
Aleran,你在 Rails 3 中使用过这种方法吗?我遇到了同样的问题,当我遇到 Michael Rykov 的这篇文章时,我正朝着连载的方向前进,但是不可能在他的博客上发表评论,或者至少在那篇文章上是不可能的。据我了解,他说您不需要定义设置类,但是当我尝试这样做时,它一直告诉我设置未定义。所以我只是想知道你是否使用过它,还有什么应该描述的?谢谢。