【问题标题】:data_mapper, attr_accessor, & serialization only serializing properties not attr_accessor attributesdata_mapper、attr_accessor 和序列化只序列化属性而不是 attr_accessor 属性
【发布时间】:2012-08-14 23:52:08
【问题描述】:

我正在使用 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 实例变量或其他东西。但即便如此,为什么呢?

【问题讨论】:

    标签: ruby sinatra ruby-datamapper attr-accessor


    【解决方案1】:

    Datamapper 有自己的序列化库 dm-serializer,它为任何 Datamapper 资源提供了一个 to_json 方法。如果您的代码中需要带有require 'data_mapper' 的Datamapper,则您使用的是data_mapper meta-gemrequires dm-serializer as part of it’s set up

    dm-serializer 提供的 to_json 方法仅序列化对象的 Datamapper 属性(即您使用 property 指定的那些),而不是“普通”属性(您使用 attr_accessor 定义的属性) )。这就是为什么你得到idfirst_name 而不是last_name

    为了避免使用dm-serializer,您需要明确要求您需要的那些库,而不是依赖data_mapper。您至少需要dm-core,也许还有其他人。

    “普通的”json 库在对对象的默认 to_json 调用中不包含任何属性,它仅使用对象 to_s 方法。所以在这种情况下,如果你用require 'dm-core' 替换require 'data_mapper',你会得到类似"\"#<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
    

    【讨论】:

    • 感谢您为我指明 dm-serializer 的方向。我对代码进行了一些研究,并意识到 :methods 参数(文档中说用于包含相关关系)也可用于包含属性。然后我覆盖了 dm-serializer 的 to_json 方法并添加了一个 :include_attributes => true 选项参数。我将发布一些代码以更好地解释。
    • @umassthrower 哦,是的,我没有注意到 methods 选项。您可以在 Person 类中执行 def to_json; super :methods => :last_name; end 以获得相同的结果。
    【解决方案2】:

    感谢马特,我做了一些挖掘并找到了 dm-serializer 的 to_json 方法的 :method 参数。他们的 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 参数。

    p ps.to_json :methods => [:last_name]
    

    或者,因为我已经有了 Base 课程:

    p ps.to_json :methods => Person.attributes
    

    现在我只需要弄清楚我想如何支持集合。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-08-04
      • 1970-01-01
      • 1970-01-01
      • 2021-05-22
      • 1970-01-01
      • 2017-03-21
      • 1970-01-01
      相关资源
      最近更新 更多