2012-09-28 56 views
2

我正在使用DataMapper進行數據庫訪問。我的目標是將模型作爲只讀對象發送到Web服務。這是我目前的嘗試:將#to_yaml添加到DataMapper模型

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: [email protected]\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 

任何想法如何使這項工作和擺脫例外?

感謝, krissi

+0

'p [u] .map(&:to_yaml)' – apneadiving

+0

這不起作用。它給了我一系列yamls。當我對陣列進行Yaml字符串yaml'd。它適用於這一層,但我需要一個乾淨的方式,無處不在 – krissi

+0

然後你必須猴子補丁陣列,並把'to_yaml'方法 – apneadiving

回答

2

使用to_yaml is deprecated in Psych,並從我的測試它似乎在這樣的情況下居然被打破。

當您直接在您的對象上調用to_yaml時,您的方法會被調用,並且您會得到期望的結果。當你在包含你的對象的數組上調用它時,Psych會序列化它,但是不能正確處理你的方法,最終返回到默認的序列化。在你的情況下,這導致嘗試序列化導致錯誤的匿名類。

要解決這個問題,您應該使用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序列化的模型,它可能是值得研究的。

+0

謝謝,很好的答案。因爲我想要點(user_foo.uid),所以不要使用結構體。我花了一些時間與包含的心理版本掙扎(它不響應'represent_object',但我現在使用捆綁器和其他東西修復了它) – krissi

+0

@krissi您使用的是什麼版本的Ruby?它看起來像'represent_object'被添加爲1.9.3,但不是在1.9.2。無論如何,如果你不能升級Ruby,你可以像你發現的那樣使用寶石中的Psych。 – matt

+0

好吧,我用1.9.2。我做了升級:) – krissi