Mongoid - 在JSON API响应中序列化DateTime字段时获取日期而不是时间

时间:2017-02-19 07:00:58

标签: ruby-on-rails json ruby datetime mongoid

我正在编写Rails应用程序,仅作为移动应用程序的Web服务。我使用--api--skip-active-record开关创建了它。我的模型有一个DateTime字段。

以下是我的模型的代码以及我在Controller中调用的方法。因为我使用--api,所以没有查看代码:

class GroceryItem
  include Mongoid::Document
  field :name, type: String
  field :expiry, type: Date
end

# grocery_items_controller.rb
# GET /grocery_items/1
def show
  render json: @grocery_item
end

在数据库中,我可以看到该字段的时间组件正在存储:

db.grocery_items.find()
{ "_id" : ObjectId("58a9298da1c1d12e7cee02d9"), "name" : "Chocolate", "expiry" : ISODate("2017-02-19T05:13:49.253Z") }

我也可以在Rails控制台中看到这个:

irb(main):003:0> GroceryItem.first
=> #<GroceryItem _id: 58a9298da1c1d12e7cee02d9, name: "Chocolate", expiry: 2017-02-19 05:13:49 UTC>

但是,当我尝试使用我的GroceryItem模型类上的方法访问到期时,我得到一个Date对象。我只得到数据的日期部分,而不是时间部分:

irb(main):004:0> GroceryItem.first.expiry
=> Sun, 19 Feb 2017

irb(main):005:0> GroceryItem.first.expiry.class
=> Date

irb(main):006:0> GroceryItem.first.expiry.to_s
=> "2017-02-19"

在实例上调用to_jsonas_json也会省略数据:

irb(main):008:0> GroceryItem.first.to_json
=> "{\"_id\":{\"$oid\":\"58a9298da1c1d12e7cee02d9\"},\"expiry\":\"2017-02-19\",\"name\":\"Chocolate\"}"

irb(main):009:0> GroceryItem.first.as_json
=> {"_id"=>BSON::ObjectId('58a9298da1c1d12e7cee02d9'), "expiry"=>Sun, 19 Feb 2017, "name"=>"Chocolate"}

这导致我的JSON响应省略了数据。我假设控制器中的渲染过程使用to_jsonas_json进行渲染:

{
    "_id": {
        "$oid": "58a9298da1c1d12e7cee02d9"
    },
    "expiry": "2017-02-19",
    "name": "Chocolate"
}

我终于能够通过调用以下内容来弄清楚如何访问这些数据。您可以看到我最终如何获得Time Ruby类:

irb(main):010:0> GroceryItem.first.attributes[:expiry]
=> 2017-02-19 05:13:49 UTC

irb(main):011:0> GroceryItem.first.attributes[:expiry].class
=> Time

这使我最终能够以与ISO8601规范兼容的方式序列化数据,以匹配MongoDB中存储的数据:

irb(main):012:0> GroceryItem.first.attributes[:expiry].utc.iso8601
=> "2017-02-19T05:13:49Z"

当然这种行为是不正确的。当开发人员为字段选择DataTime类型时,他们必须希望时间组件通过。否则,他们将使用日期类型。我现在明白,我可以通过创建一个以我认为合适的方式呈现JSON的视图来覆盖默认的Rails API和Mongoid配对行为,但我正在考虑提交错误报告,因为我觉得默认行为应该自动更改为当开发人员选择DateTime字段类型时,呈现存储在数据库中的所有数据。

在我继续提交错误报告之前,我想知道这里是否有人对此问题有任何意见。

1 个答案:

答案 0 :(得分:1)

问题似乎出现在您的代码中:

class GroceryItem
  include Mongoid::Document
  field :name, type: String
  field :expiry, type: Date
end

此处,到期时间类型为日期,因此预计会返回没有时间成分的日期。我认为使用适当的类型将解决您的问题。