在序列化哈希时,ActiveRecord将符号键转换为字符串

时间:2012-09-18 19:08:22

标签: ruby-on-rails activerecord yaml

我有一个带有序列化Hash属性的Rails模型类,如下所示:

class Action
  serialize :metadata, Hash
  # . . .
end

该列存储在具有YAML编码的text列中。问题是当我将metadata值传递给create!方法时,散列键会从符号转换为字符串,但该转换不会在其他时间发生。例如:

$ rails console
> a = Action.create!(:metadata => {:foo => "bar"})
> a.metadata
 => {"foo"=>"bar"}
> a.metadata[:fizz] = "buzz"
> a.metadata
 => {"foo"=>"bar", :fizz=>"buzz"}

现在,当我保存模型时,数据库将具有此文本值:

---
foo: bar
:fizz: buzz

有任何建议如何解决这个问题?

(这是使用Rails 3.0.16。)

3 个答案:

答案 0 :(得分:3)

我自己回答这个问题,并提出@ Mori建议的变体:

class Action < ActiveRecord::Base
  def metadata=(v)
    self[:metadata] = v.try(:symbolize_keys!)
  end
end

据我所知,这可以在不破坏其他地方界面的情况下解决问题。我想如果我想要一个键成为一个字符串,这个方法会让我感到讨厌,但事实并非如此,所以我比其他人提出的意外更愿意接受它。的解决方案。

不过,如果有人可以提出一个根本不需要这种解决方法的解决方案,我很乐意接受这个作为正确的答案。

答案 1 :(得分:2)

class Action < ActiveRecord::Base
  def metadata
    self[:metadata].try :symbolize_keys
  end
end

答案 2 :(得分:0)

我最后走了另一条路。当我访问属性时,我确保得到HashWithIndifferentAccess

def metadata
  return self[:metadata] if self[:metadata].is_a?(HashWithIndifferentAccess)
  self[:metadata] = HashWithIndifferentAccess.new(self[:metadata])
end

额外的好处是,如果metadata未设置,我将获得空哈希而不是nil