ruby-on-rails - 为什么渲染 json : is returning NULL instead of boolean value

标签 ruby-on-rails

为什么我收到 null而不是 真/假对于 is_read 从 API 调用资源时?
问题:可能与render json:有关内部?
这是我第一次看到这个巫术,所以请多多包涵。寻找好的答案:)

$ curl -X GET -H localhost:3000/api/v1/alerts/1/show | python -m json.tool


{
    "body": "Deserunt laboriosam quod consequuntur est dolor cum molestias.",
    "created_at": "2015-03-22T15:02:01.927Z",
    "id": 1,
    "is_read": null,
    "subtitle": "Aspernatur non voluptatem minus qui laudantium molestiae.",
    "title": "Et nemo magni autem similique consequuntur.",
    "updated_at": "2015-03-22T15:02:01.927Z"
}
-i
HTTP/1.1 200 OK
X-Frame-Options: SAMEORIGIN
X-Xss-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Content-Type: application/json; charset=utf-8
Etag: "3232ec2058ffb13db1f9244366fe2ea8"
Cache-Control: max-age=0, private, must-revalidate
X-Request-Id: c520cabe-6334-4997-956b-d1f21724b80c
X-Runtime: 0.016337
Server: WEBrick/1.3.1 (Ruby/2.1.2/2014-05-08)
Date: Sun, 22 Mar 2015 15:28:21 GMT
Content-Length: 300
Connection: Keep-Alive
Rails 控制台:
Alert.find(1)
  Alert Load (1.1ms)  SELECT  "alerts".* FROM "alerts"  WHERE "alerts"."id" = $1 LIMIT 1  [["id", 1]]
=> #<Alert id: 1, title: "Et nemo magni autem similique consequuntur.", subtitle: "Aspernatur non voluptatem minus qui laudantium mol...", body: "Deserunt laboriosam quod consequuntur est dolor cu...", is_read: false, created_at: "2015-03-22 15:02:01", updated_at: "2015-03-22 15:02:01">
当我调用 #to_json 时会发生奇怪的事情
Alert.find(1).to_json
  Alert Load (4.1ms)  SELECT  "alerts".* FROM "alerts"  WHERE "alerts"."id" = $1 LIMIT 1  [["id", 1]]
=> "{\"id\":1,\"title\":\"Et nemo magni autem similique consequuntur.\",\"subtitle\":\"Aspernatur non voluptatem minus qui laudantium molestiae.\",\"body\":\"Deserunt laboriosam quod consequuntur est dolor cum molestias.\",\"is_read\":null,\"created_at\":\"2015-03-22T15:02:01.927Z\",\"updated_at\":\"2015-03-22T15:02:01.927Z\"}"
当 is_read 为真时也会发生这种情况。
更多信息:
Rails 4.1.7、Ruby 2.1.2、Postgresql
警报
create_table "alerts", force: true do |t|
  t.string   "title"
  t.string   "subtitle"
  t.text     "body"
  t.boolean  "is_read",    default: false, null: false
  t.datetime "created_at"
  t.datetime "updated_at"
end
用于填充数据库的脚本:
Alert.populate 100 do |alert|
  alert.title = Faker::Lorem.sentence(3)
  alert.subtitle = Faker::Lorem.sentence(3)
  alert.body = Faker::Lorem.sentence(3)
  alert.is_read = false
end
Controller :
def show
  alert = Alert.find(params[:id])
  render json: alert
end
PostgreSQL
编辑 2015 年 3 月 26 日
irb(main):013:0> Alert.find(1)
  Alert Load (0.6ms)  SELECT  "alerts".* FROM "alerts"  WHERE "alerts"."id" = $1 LIMIT 1  [["id", 1]]
=> #<Alert id: 1, title: "Test", subtitle: "waaat?", body: "heeeelp", is_read: false, created_at: "2015-03-26 15:49:32", updated_at: "2015-03-26 15:56:51">
irb(main):014:0> a.body
=> "heeeelp"
irb(main):015:0> a.title
=> "Test"
irb(main):016:0> a.is_read
=> nil
irb(main):017:0> a["is_read"]
=> false
irb(main):018:0> a.update_attributes(is_read: true)
   (0.4ms)  BEGIN
  SQL (0.5ms)  UPDATE "alerts" SET "is_read" = $1, "updated_at" = $2 WHERE "alerts"."id" = 1  [["is_read", "t"], ["updated_at", "2015-03-26 15:57:26.645210"]]
   (2.1ms)  COMMIT
=> true
irb(main):019:0> a["is_read"]
=> true
最终:这是因为模型中有 attr_reader :is_read 。删除它将导致正确的序列化。有人可以解释一下吗?

最佳答案

Final: it was because there was attr_reader :is_read in the model. Removing that it will result in a correct serialization. Can someone explain this?



ActiveRecord 通过为每个属性创建一个 getter 方法来帮助将数据库字段映射到 Ruby 类上的方法,该方法从内部属性存储(变量)中提取值。

当您定义 attr_reader :is_read ,这实际上是以下的简写:
# app/mode/alert.rb    
def is_read
  @is_read
end
ActiveRecord::Base 提供的你的 getter 方法将被这个新定义的方法掩盖。这可能是出乎意料的,而且乍一看绝对像是巫术。
:attr_reader 的行为是(有点稀疏)记录在这里:

Creates instance variables and corresponding methods that return the value of each instance variable.



http://ruby-doc.org/core-1.9.3/Module.html#method-i-attr_reader

But why then it is coming as null? Could be related to render json: internals?



这个问题有两个部分。

首先,为什么值(value)不存在?上面已经给出了答案。您的模型掩盖了 ActiveRecord getter 方法 is_read ,指向 ActiveRecord 的内部属性存储,其中一个指向实例变量 @is_read .因为你没有分配 @is_read在您的模型中,nil被退回。

其次,为什么是null而不是 nil ?正如你所暗示的,这个问题的答案与 render: json 相关。 .在 JSON specification ,您有以下允许的值:

string, number, object, array, true, false, null



要生成有效的 JSON 响应,render: json替换 Ruby 的 nil , 使用 JSON 的 null .

那么说你永远不想使用 attr_reader 是否安全? , attr_accessor等。人。在你的模型中?并不真地。这些可以用作虚拟或 transient 属性,一旦对象被销毁,这些属性就会丢失。但是,应该记住与 ActiveRecord 的交互,以避免遇到看似晦涩难懂的错误。

关于ruby-on-rails - 为什么渲染 json : is returning NULL instead of boolean value,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29196074/

相关文章:

ruby-on-rails - ASCII-8BIT 中的 Rails 编码

mysql - Rails 4 ActiveRecord - 如何查看如何解释数据库查询?

javascript - rails 。 jQuery 表单提交字段模糊

ruby-on-rails - Rails 4 添加位置 header

ruby-on-rails - 考虑使用现有数据(不是数据库,实际数据)的新 Rails 应用程序——最好的处理方法是什么?

ruby-on-rails - Rails 的一个数据库条目的三个文本字段

ruby-on-rails - 带有模块和命名空间的 form_for

ruby-on-rails - 之前(:each) vs just before

ruby-on-rails - 在 ruby​​ on rails 中将 collection_action 方法添加到事件管理中的顶部菜单项

ruby-on-rails - 工厂女孩: uninitialized constant