为什么在从API调用资源时,我得到null
的是is_read而不是true/false?
否定:可能与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"
}
Run Code Online (Sandbox Code Playgroud)
-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
Run Code Online (Sandbox Code Playgroud)
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">
Run Code Online (Sandbox Code Playgroud)
当我打电话时,会发生奇怪的事情 #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\"}"
Run Code Online (Sandbox Code Playgroud)
当is_read为true时,也会发生这种情况.
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
Run Code Online (Sandbox Code Playgroud)
用于填充db的脚本:
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
Run Code Online (Sandbox Code Playgroud)
控制器:
def show
alert = Alert.find(params[:id])
render json: alert
end
Run Code Online (Sandbox Code Playgroud)
编辑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
Run Code Online (Sandbox Code Playgroud)
最后:因为模型中有attr_reader:is_read.删除它将导致正确的序列化.有人可以解释一下吗?
最后:因为模型中有attr_reader:is_read.删除它将导致正确的序列化.有人可以解释一下吗?
ActiveRecord通过为每个属性创建一个getter方法,帮助将数据库字段映射到Ruby类的方法,从内部属性存储(变量)中提取值.
定义时attr_reader :is_read
,实际上是简写:
# app/mode/alert.rb
def is_read
@is_read
end
Run Code Online (Sandbox Code Playgroud)
您手动提供的getter方法ActiveRecord::Base
将被这个新定义的方法屏蔽.这可能是意料之外的,一开始看起来绝对像巫术.
这里记录的行为:attr_reader
(有点稀疏):
创建实例变量和返回每个实例变量值的相应方法.
http://ruby-doc.org/core-1.9.3/Module.html#method-i-attr_reader
但为什么它会变为空?可能与渲染json:internals有关吗?
这个问题分为两部分.
首先,为什么价值不存在?上面给出了答案.您的模型已经屏蔽了ActiveRecord getter方法is_read
,该方法是针对ActiveRecord的内部属性存储,其中一个指向实例变量@is_read
.因为您没有@is_read
在模型中分配,所以nil
会返回.
其次,为什么null
不nil
呢?正如你所暗示的,答案就是这个问题render: json
.在JSON规范中,您具有以下允许值:
string,number,object,array,true,false,null
为了产生有效的JSON响应,render: json
Ruby的替代nil
,使用JSON的null
.
因此,它是安全的,然后说,你永远不想用attr_reader
,attr_accessor
等.人.在你的模特?并不是的.这些可以用作虚拟或瞬态属性,一旦对象被销毁就会丢失.但是,应该记住与ActiveRecord的交互,以避免遇到看似晦涩的错误.