【问题标题】:Adding #to_yaml to DataMapper models将 #to_yaml 添加到 DataMapper 模型
【发布时间】:2012-09-28 09:45:48
【问题描述】:

我正在使用 DataMapper 进行数据库访问。我的目标是将模型作为只读对象发送到 Web 服务。这是我目前的尝试:

class User
  include DataMapper::Resource

  def to_yaml(opts = {})
    mini_me = OpenStruct.new
    instance_variables.each do |var|
      next if /^@_/ =~ var.to_s
      mini_me.send("#{var.to_s.gsub(/^@/, '')}=", instance_variable_get(var))
    end

    mini_me.to_yaml(opts)
  end

  ....
end

YAML::ENGINE.yamler = 'psych'

u = User.get("hulk")
p u.to_yaml
# => "--- !ruby/object:OpenStruct\ntable:\n  :uid: hulk\n  :uidNumber: 1000\n  :gidNumber: 1001\n  :email: hulk@example.com\n  :dn: uid=hulk,ou=People,o=example\n  :name: Hulk\n  :displayName: Hulk\n  :description: Hulk\n  :homeDirectory: /home/hulk\n  :accountFlags: ! '[U          ]'\n  :sambaSID: S-1-5-21-......\nmodifiable: true\n" 

p [ u ].to_yaml # TypeError: can't dump anonymous class Class

任何想法如何使这项工作并摆脱异常?

谢谢, 克里斯

【问题讨论】:

  • p [ u ].map(&:to_yaml)
  • 这不起作用。它给了我一系列 yamls。当我对数组进行 yaml 处理时,我会得到 yaml 字符串 yaml'd。它适用于这一层,但我需要一种适用于任何地方的干净方式
  • 那么你必须修改 Array 并在那里放置一个to_yamlmethod
  • Array 确实支持 #to_yaml: [:coffee].to_yaml 按预期工作

标签: ruby yaml psych


【解决方案1】:

使用to_yaml is deprecated in Psych,根据我的测试,在这种情况下它似乎实际上被破坏了。

当你直接在你的对象上调用to_yaml 时,你的方法会被调用并且你会得到你期望的结果。当您在包含您的对象的数组上调用它时,Psych 会对其进行序列化,但无法正确处理您的 to_yaml 方法,并最终退回到默认序列化。在您的情况下,这会导致尝试序列化导致错误的匿名类。

要解决此问题,您应该改用encode_with 方法。如果在生成的 yaml 中将序列化表单标记为 OpenStruct 对象很重要,您可以使用represent_object(第一个nil 参数似乎没有使用):

def encode_with(coder)
  mini_me = OpenStruct.new
  instance_variables.each do |var|
    next if /^@_/ =~ var.to_s
    mini_me.send("#{var.to_s.gsub(/^@/, '')}=", instance_variable_get(var))
  end

  coder.represent_object(nil, mini_me)
end

如果您只是为了方便而使用 OpenStruct,则替代方法可能是:

def encode_with(coder)
  instance_variables.each do |var|
    next if /^@_/ =~ var.to_s
    coder[var.to_s.gsub(/^@/, '')]= instance_variable_get(var)
  end
end

请注意,Datamapper has its own serializer plugin 为模型提供 yaml 序列化,可能值得研究。

【讨论】:

  • 谢谢,很好的回答。我会保留结构,因为我想要点(user_foo.uid)。我花了一些时间来处理包含的心理版本(它不响应represent_object,但我用捆绑器修复了它,现在一切都很好;)
  • @krissi 您使用的是什么版本的 Ruby?看起来 represent_object 是为 1.9.3 添加的,但不在 1.9.2 中。无论如何,如果你不能升级 Ruby,你可以像你发现的那样使用 gem 中的 Psych。
  • 好吧,我用的是 1.9.2。我做升级:)
猜你喜欢
  • 1970-01-01
  • 2016-01-06
  • 2013-01-29
  • 2023-03-10
  • 1970-01-01
  • 2020-03-24
  • 2020-04-18
  • 2018-01-23
  • 2014-12-02
相关资源
最近更新 更多