我正在使用data_mapper / sinatra并尝试使用attr_accessor创建一些属性。以下示例代码:
require 'json'
class Person
include DataMapper::Resource
property :id, Serial
property :first_name, String
attr_accessor :last_name
end
ps = Person.new
ps.first_name = "Mike"
ps.last_name = "Smith"
p ps.to_json
生成此输出:
"{\"id\":null,\"first_name\":\"Mike\"}"
显然我希望它能给我名字和姓氏属性。关于如何让人们按照预期的方式工作以使我的json拥有所有属性的任何想法?
另外,请随意解释为什么我的期望(我得到所有属性)不正确。我猜一些内部属性列表没有将attr_accessor实例变量添加到它或其他东西。但即便如此,为什么呢?
答案 0 :(得分:2)
Datamapper拥有自己的序列化库dm-serializer
,可为任何Datamapper资源提供to_json
方法。如果您的代码中需要带有require 'data_mapper'
的Datamapper,那么您使用data_mapper
meta-gem requires dm-serializer as part of it’s set up。{/ p>
to_json
提供的dm-serializer
方法仅序列化对象的Datamapper属性(即您使用property
指定的属性),而不是“正常”属性(即您用attr_accessor
定义。这就是您获得id
和first_name
但不是last_name
的原因。
为了避免使用dm-serializer
,您需要明确要求所需的库,而不是依赖data_mapper
。您至少需要dm-core
和其他人。
“普通”json
库在对象的默认to_json
调用中不包含任何属性,它只使用对象to_s
方法。因此,在这种情况下,如果您将require 'data_mapper'
替换为require 'dm-core'
,您将获得类似"\"#<Person:0x000001013a0320>\""
的内容。
要创建自己对象的json表示,您需要创建自己的to_json
方法。一个简单的例子就是在json中对你想要的属性进行硬编码:
def to_json
{:id => id, :first_name => first_name, :last_name => last_name}.to_json
end
您可以创建一个方法来查看对象的属性和属性,并从中创建适当的json,而不是以这种方式对其进行硬编码。
请注意,如果您创建自己的to_json
方法,仍然可以致电require 'data_mapper'
,则to_json
将替换dm-serializer
提供的方法。实际上,dm-serializer
还添加了as_json
method,您可以使用它来创建合并的to_json
方法,例如:
def to_json
as_json.merge({:last_name => last_name}).to_json
end
答案 1 :(得分:1)
感谢Matt我做了一些挖掘并找到了dm-serializer的to_json方法的方法参数。他们的to_json方法相当不错,基本上只是as_json辅助方法的包装器,所以我通过添加几行来覆盖它:
if options[:include_attributes]
options[:methods] = [] if options[:methods].nil?
options[:methods].concat(model.attributes).uniq!
end
完成的方法覆盖如下所示:
module DataMapper
module Serializer
def to_json(*args)
options = args.first
options = {} unless options.kind_of?(Hash)
if options[:include_attributes]
options[:methods] = [] if options[:methods].nil?
options[:methods].concat(model.attributes).uniq!
end
result = as_json(options)
# default to making JSON
if options.fetch(:to_json, true)
MultiJson.dump(result)
else
result
end
end
end
end
这与我添加到我用于模型的基本模块中的属性方法一起使用。相关部分如下:
module Base
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def attr_accessor(*vars)
@attributes ||= []
@attributes.concat vars
super(*vars)
end
def attributes
@attributes || []
end
end
def attributes
self.class.attributes
end
end
现在我原来的例子:
require 'json'
class Person
include DataMapper::Resource
include Base
property :id, Serial
property :first_name, String
attr_accessor :last_name
end
ps = Person.new
ps.first_name = "Mike"
ps.last_name = "Smith"
p ps.to_json :include_attributes => true
使用新选项参数按预期工作。
我可以做的就是有选择地获取我想要的属性而不必做额外的工作就是将属性名称传递给:methods param。
p ps.to_json :methods => [:last_name]
或者,因为我已经有了Base
课程:
p ps.to_json :methods => Person.attributes
现在我只需要弄清楚我想如何支持集合。