【问题标题】:Have to_json return a mongoid as a string让 to_json 返回一个 mongoid 作为字符串
【发布时间】:2014-05-06 21:58:56
【问题描述】:

在我的 Rails API 中,我希望 Mongo 对象以 JSON 字符串的形式返回,Mongo UID 作为“id”属性而不是“_id”对象。

我希望我的 API 返回以下 JSON:

{
    "id": "536268a06d2d7019ba000000",
    "created_at": null,
}

代替:

{
    "_id": {
        "$oid": "536268a06d2d7019ba000000"
    },
    "created_at": null,
}

我的型号代码是:

class Profile
  include Mongoid::Document
  field :name, type: String

  def to_json(options={})
    #what to do here?
    # options[:except] ||= :_id  #%w(_id)
    super(options)
  end
end

【问题讨论】:

    标签: ruby-on-rails mongoid


    【解决方案1】:

    你可以猴子补丁Moped::BSON::ObjectId:

    module Moped
      module BSON
        class ObjectId   
          def to_json(*)
            to_s.to_json
          end
          def as_json(*)
            to_s.as_json
          end
        end
      end
    end
    

    处理$oid 的东西,然后Mongoid::Document_id 转换为id

    module Mongoid
      module Document
        def serializable_hash(options = nil)
          h = super(options)
          h['id'] = h.delete('_id') if(h.has_key?('_id'))
          h
        end
      end
    end
    

    这将使您所有的 Mongoid 对象的行为都变得合理。

    【讨论】:

    • 我假设第一个块允许正确保存返回的对象,尽管第二个。
    • @zishe 第一个给你"536268a06d2d7019ba000000"而不是{"$oid":"536268a06d2d7019ba000000"},第二个在JSON中用"id"替换"_id"
    • 我明白了:) 我只是想指出一个事实,即如果某些带有前端部分的 api 可以修改此对象然后发送请求保存它,它将不起作用。它主要与 @MonkeyBonkey 作为警告有关,而不是与您作为 en 错误的解决方案有关。
    • @zishe 如果您遵循通常的模式应该可以正常工作:m = Model.find(id); m.update_attributes(...)。还是我错过了什么?我不是想挑衅,我真的很好奇我是否遗漏了什么,或者有什么不清楚的地方。
    • 是的,你可能是对的。我做了同样的事情,所以想要准确。
    【解决方案2】:

    对于使用 Mongoid 4+ 的人,请使用这个,

    module BSON
      class ObjectId
        alias :to_json :to_s
        alias :as_json :to_s
      end
    end
    

    Reference

    【讨论】:

    • 请不要。我只花了 2 个小时调试一些非常奇怪的行为,结果发现这段代码(复制/粘贴到代码库中)是罪魁祸首。 to_s 不像 as_json 那样采用可选参数。 @mu 太短的答案说明了这一点。此外,覆盖该方法至少会在堆栈跟踪中显示猴子补丁。与原始方法隔离的别名将更难找到。
    【解决方案3】:

    您可以在as_json方法中更改数据,而数据是哈希:

    class Profile
      include Mongoid::Document
      field :name, type: String
    
       def as_json(*args)
        res = super
        res["id"] = res.delete("_id").to_s
        res
      end
    end
    
    p = Profile.new
    p.to_json
    

    结果:

    {
        "id": "536268a06d2d7019ba000000",
        ...
    }
    

    【讨论】:

    • 不错,不需要猴子补丁,具体型号也很清楚。
    【解决方案4】:

    用例:

    user = collection.find_one(...)
    user['_id'] = user['_id'].to_s
    user.to_json
    

    这个返回

    {
        "_id": "54ed1e9896188813b0000001"
    }
    

    【讨论】:

      【解决方案5】:
      class Profile
        include Mongoid::Document
        field :name, type: String
        def to_json
          as_json(except: :_id).merge(id: id.to_s).to_json
        end
      end
      

      【讨论】:

        【解决方案6】:

        如果你不想改变 MongoId 的默认行为,只需转换 as_json 的结果即可。

        profile.as_json.map{|k,v| [k, v.is_a?(BSON::ObjectId) ? v.to_s : v]}.to_h
        

        此外,这会转换其他BSON::ObjectId,例如user_id

        【讨论】:

          【解决方案7】:
          # config/initializers/mongoid.rb
          
          # convert object key "_id" to "id" and remove "_id" from displayed attributes on mongoid documents when represented as JSON
          module Mongoid
            module Document
              def as_json(options={})
                attrs = super(options)
                id = {id: attrs["_id"].to_s}
                attrs.delete("_id")
                id.merge(attrs)
              end
            end
          end
          
          # converts object ids from BSON type object id to plain old string
          module BSON
            class ObjectId
              alias :to_json :to_s
              alias :as_json :to_s
            end
          end
          

          【讨论】:

            猜你喜欢
            • 2017-09-22
            • 2017-03-11
            • 2014-12-11
            • 1970-01-01
            • 2012-12-18
            • 1970-01-01
            • 2013-03-31
            • 1970-01-01
            • 2018-10-17
            相关资源
            最近更新 更多