2

私は 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 インスタンス変数が追加されていないか、何かを推測していると思います。なのに、どうして?

4

2 に答える 2

2

Datamapper には、任意の Datamapper リソースにメソッドをdm-serializer提供する独自のシリアル化ライブラリ があります。コードでto_jsonDatamapper が必要な場合は、セットアップの一部として dm-serializerを必要とするメタジェムを使用しています。require 'data_mapper'data_mapper

to_jsonによって提供されるメソッドはdm-serializer、オブジェクトの Datamapper プロパティ (つまり、 で指定したものproperty) のみをシリアライズし、「通常の」プロパティ ( で定義したものattr_accessor) はシリアライズしません。idこれが、 andfirst_nameが得られない理由ですlast_name

の使用を避けるdm-serializerには、に依存するのではなく、必要なライブラリを明示的に要求する必要がありますdata_mapper。少なくともdm-core、おそらく他の人が必要になります。

「通常の」ライブラリには、オブジェクトjsonのデフォルトの呼び出しに属性は含まれず、objectsメソッドを使用するだけです。したがって、この場合、 に置き換えると、 のようなものが得られます。to_jsonto_srequire '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_jsonto_json

def to_json
  as_json.merge({:last_name => last_name}).to_json
end
于 2012-08-19T07:34:08.530 に答える
1

Matt のおかげで、いくつか掘り下げて、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

次に、コレクションをどのようにサポートしたいかを理解する必要があります。

于 2012-08-20T05:08:36.153 に答える