Ruby-on-rails ActiveRecord 使用 JSON 而不是 YAML 进行序列化

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2080347/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 22:09:33  来源:igfitidea点击:

ActiveRecord serialize using JSON instead of YAML

ruby-on-railsjsonactiverecordyamlserialization

提问by Toby Hede

I have a model that uses a serialized column:

我有一个使用序列化列的模型:

class Form < ActiveRecord::Base
  serialize :options, Hash
end

Is there a way to make this serialization use JSON instead of YAML?

有没有办法让这个序列化使用 JSON 而不是 YAML?

回答by Justas L.

In Rails 3.1 you can just

在 Rails 3.1 中,你可以

class Form < ActiveRecord::Base
  serialize :column, JSON
end

Hope that helps

希望有帮助

回答by balu

In Rails 3.1 you can use custom coders with serialize.

在 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

Hope this helps.

希望这可以帮助。

References:

参考:

Definition of serialize: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/base.rb#L556

定义serializehttps: //github.com/rails/rails/blob/master/activerecord/lib/active_record/base.rb#L556

The default YAML coder that ships with rails: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/coders/yaml_column.rb

Rails 附带的默认 YAML 编码器:https: //github.com/rails/rails/blob/master/activerecord/lib/active_record/coders/yaml_column.rb

And this is where the call to the loadhappens: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/attribute_methods/read.rb#L132

这就是调用load发生的地方:https: //github.com/rails/rails/blob/master/activerecord/lib/active_record/attribute_methods/read.rb#L132

回答by St.Woland

Update

更新

See mid's high rated answer below for a much more appropriate Rails >= 3.1 answer. This is a great answer for Rails < 3.1.

有关更合适的 Rails >= 3.1 答案,请参阅下面的中等评分答案。这是 Rails < 3.1 的一个很好的答案。

Probably this is what you're looking for.

可能这就是你要找的。

Form.find(:first).to_json

Update

更新

1) Install 'json' gem:

1)安装'json' gem

gem install json

2) Create JsonWrapper class

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) Add model callbacks:

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) Test it!

4) 测试一下!

User.create :name => {"a"=>"b", "c"=>["d", "e"]}

PS:

PS:

It's not quite DRY, but I did my best. If anyone can fix after_findin Usermodel, it'll be great.

不是很干,但我尽力了。如果任何人都可以修复after_findUser模型,这将是巨大的。

回答by Toby Hede

My requirements didn't need a lot of code re-use at this stage, so my distilled code is a variation on the above answer:

我的需求在这个阶段不需要大量代码重用,所以我的提炼代码是上述答案的变体:

  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  

Cheers, quite easy in the end!

干杯,最后很容易!

回答by caribu

The serialize :attr, JSONusing composed_ofmethod works like this:

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) }

where url is the attribute to be serialized using json and auth is the new method available on your model that saves its value in json format to the url attribute. (not fully tested yet but seems to be working)

其中 url 是要使用 json 序列化的属性,auth 是模型上可用的新方法,它将其值以 json 格式保存到 url 属性。(尚未完全测试,但似乎正在工作)

回答by Benjamin Atkin

I wrote my own YAML coder, that takes a default. Here is the class:

我编写了自己的 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

Since loadand dumpare instance methods it requires an instance to be passed as the second argument to serializein the model definition. Here's an example of it:

由于loaddump是实例方法,它需要一个实例作为serialize模型定义中的第二个参数传递。这是一个例子:

class Person < ActiveRecord::Base
  validate :name, :pets, :presence => true
  serialize :pets, JSONColumn.new([])
end

I tried creating a new instance, loading an instance, and dumping an instance in IRB, and it all seemed to work properly. I wrote a blog postabout it, too.

我尝试创建一个新实例,加载一个实例,并在 IRB 中转储一个实例,一切似乎都正常工作。我也写了一篇关于它的博客文章

回答by Aleran

A simpler solution is to use composed_ofas described in this blog post by Michael Rykov. I like this solution because it requires the use of fewer callbacks.

一个更简单的解决方案是composed_of按照Michael Rykov 的这篇博客文章中的描述使用。我喜欢这个解决方案,因为它需要使用更少的回调。

Here is the gist of it:

这是它的要点:

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

回答by Andrew Lank

Aleran, have you used this method with Rails 3? I've somewhat got the same issue and I was heading towards serialized when I ran into this post by Michael Rykov, but commenting on his blog is not possible, or at least on that post. To my understanding he is saying that you do not need to define Settings class, however when I try this it keeps telling me that Setting is not defined. So I was just wondering if you have used it and what more should have been described? Thanks.

Aleran,您在 Rails 3 中使用过这种方法吗?我遇到了同样的问题,当我遇到 Michael Rykov 的这篇文章时,我正朝着连载的方向前进,但不可能在他的博客上发表评论,或者至少在那篇文章上发表评论是不可能的。据我了解,他是说您不需要定义 Settings 类,但是当我尝试此操作时,它一直告诉我未定义 Setting 。所以我只是想知道你是否使用过它,还有什么应该被描述的?谢谢。