【问题标题】:ActiveRecord converts symbol keys to strings when serializing my hashActiveRecord 在序列化我的哈希时将符号键转换为字符串
【发布时间】:2012-09-11 02:15:38
【问题描述】:

我有一个带有序列化 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。)

【问题讨论】:

  • 它是否表现出与serialize :metadata, HashWithIndifferentAccess 相同的行为?
  • @gregates:我试过了,这意味着我可以用字符串或符号查询哈希并获取值,但是有两个问题:Action.create!(:metadata => {:foo => :bar}) 引发异常,因为我不是不再允许传递普通的 Hash,并且Action.find(an_old_id) 引发了 SerializationTypeMismatch 异常,因为 Rails 不知道如何将 YAML 转换为 HashWithIndifferentAccess。

标签: ruby-on-rails activerecord yaml


【解决方案1】:
class Action < ActiveRecord::Base
  def metadata
    self[:metadata].try :symbolize_keys
  end
end

【讨论】:

  • 这是一个不错的建议,但现在如果我说 a.metadata[:foo] = 'bar' 更改将丢失,因为我分配给哈希的副本,而不是模型引用的哈希。
  • 。 . .但是,如果我改为使用self[:metadata].try :symbolize_keys!,它确实 起作用。不过,这感觉有点不对。
【解决方案2】:

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

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

据我所知,这可以解决问题而不会破坏其他地方的界面。我想如果我想要一个键是一个字符串,这个方法会给我一个令人讨厌的惊喜,但事实并非如此,所以我更愿意接受它而不是其他提议的惊喜解决方案。

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

【讨论】:

    【解决方案3】:

    我最终选择了另一条路线。当我访问该属性时,我确保我得到一个 HashWithIndifferentAccess

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

    另外一个好处是,如果 metadata 没有设置,我会得到一个空哈希而不是 nil

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-10-31
      • 2012-12-12
      • 1970-01-01
      • 1970-01-01
      • 2010-10-22
      • 2011-05-19
      • 2015-08-24
      • 2016-10-21
      相关资源
      最近更新 更多