Rails中的PUT请求不会更新response_with调用的状态 [英] PUT requests in rails don't update the status on respond_with calls
问题描述
给出以下导轨控制器:
class AccountsController < ApplicationController
respond_to :json, :xml
def update
@account = Account.where(uuid: params[:id]).first
unless @account.nil?
if @account.update_attributes params[:account]
respond_with @account, location: account_url(@account)
else
respond_with error_hash, status: :unprocessable_entity, root: :error, location: api_account_url(@account)
end
else
respond_with error_hash, status: :not_found, root: :error, location: accounts_url
end
end
def error_hash
{ :example => "Example for this question", :parameter => 42 }
end
end
我希望对/accounts/update/的PUT
请求能够执行以下操作
I would expect a PUT
request to /accounts/update/ to do the following
- 如果id存在,并且update_attributes调用成功,则发送
204 (No Content)
成功消息. (我将它设置为返回@account,这很好,但没什么大不了的.这里的204很好.) - 如果id存在,但是数据不正确,请提供
422 (Unprocessable Entity)
错误消息以及xml/json来表示错误. - 如果id不存在,请提供
404 (Not Found)
错误消息以及xml/json来表示错误.
- If the id exists, and the update_attributes call succeeds, deliver a
204 (No Content)
success message. (I have it set to return @account, which would be nice, but no big deal. 204 is fine here.) - If the id exists, but the data is bad, deliver a
422 (Unprocessable Entity)
error message, along with the xml/json to represent the error. - If the id does not exist, deliver a
404 (Not Found)
error message, along with the xml/json to represent the error.
实际发生的是:
- 交付没有尸体的204.
- 交付没有尸体的204.
- 交付没有尸体的204.
为什么它忽略了我的身份和身体?对于GET
请求,我也有类似的设置,可以很好地解决问题(正确的状态,正确的正文).
Why is it that it ignores both my status and my body? I've had a similar setup for GET
requests that work out just fine (correct status, correct body).
示例CURL
请求(对于不存在的ID):
Example CURL
request (for an ID that does not exist):
PUT
请求
curl -i --header "Accept: application/xml" --header "Content-type: application/json" -X PUT -d '{"name": "whoop"}' http://localhost:3000/api/accounts/3d2cc5d0653911e2aaadc82a14fffee9
HTTP/1.1 204 No Content
Location: http://localhost:3000/api/accounts
X-Ua-Compatible: IE=Edge
Cache-Control: no-cache
X-Request-Id: bf0a02f452fbace65576aab6d2bd7c1e
X-Runtime: 0.029193
Server: WEBrick/1.3.1 (Ruby/1.9.3/2013-01-15)
Date: Thu, 24 Jan 2013 08:01:31 GMT
Connection: close
Set-Cookie: _bankshare_session=BAh7BkkiD3Nlc3Npb25faWQGOgZFRkkiJWFmNmI2MmU0MzViMmE3N2YzMDIzOTdjMDJmZDhiMzEwBjsAVA%3D%3D--133e394eb760a7fce07f1fd51349dc46c2d51626; path=/; HttpOnly
GET
请求
curl -i --header "Accept: application/json" --header "Content-type: application/json" -X GET http://localhost:3000/api/accounts/3d2cc5d0653911e2aaadc82a14fffee9
HTTP/1.1 404 Not Found
Content-Type: application/json; charset=utf-8
X-Ua-Compatible: IE=Edge
Cache-Control: no-cache
X-Request-Id: 9cc0d1cdfb27bb86a206cbc38cd75473
X-Runtime: 0.005118
Server: WEBrick/1.3.1 (Ruby/1.9.3/2013-01-15)
Date: Thu, 24 Jan 2013 08:19:45 GMT
Content-Length: 116
Connection: Keep-Alive
{"friendly-status":"not-found","status":404,"message":"No account with id '3d2cc5d0653911e2aaadc82a14fffee9' found"}
推荐答案
根据此讨论这种相当不直观的行为是由于希望保持与支架的兼容性.
According to this discussion this rather non intuitive behavior is due to the desire to maintain compatibility with the scaffold.
通常,我们将响应者的实现方式与 脚手架.这使我们可以说:用response_with替换response_to 一切都会完全一样.
In general we keep the responder the same implementation as the scaffold. This allows us to say: replace respond_to by respond_with and everything will work exactly the same.
- josevalim
您有两种选择来覆盖默认行为.
You have two choices to override the default behavior.
unless @account.nil?
if @account.update_attributes params[:account]
respond_with @account do |format|
format.json { render json: @account.to_json, status: :ok }
format.xml { render xml: @account.to_xml, status: :ok }
end
else
respond_with error_hash do |format|
format.json { render json: error_hash.to_json(root: :error), status: :unprocessable_entity }
format.xml { render xml: error_hash.to_xml(root: :error), status: :unprocessable_entity }
end
end
else
respond_with error_hash do |format|
format.json { render json: error_hash.to_json(root: :error), status: :not_found }
format.xml { render xml: error_hash.to_xml(root: :error), status: :not_found }
end
end
不幸的是,对于每种格式,我们都必须重新进行复制,但这似乎是到目前为止对Rails 4.0的最新建议.参见此处.
It's unfortunate that we have to return to duplication for each format, but that seems to be the current recommendation up to Rails 4.0 so far; see here.
如果您要返回更新的对象,则应该返回 200-确定,而不是 204-无内容,或者不返回任何内容并使客户代码为"GET" '更新的对象. :location在api上下文中没有意义,它用于重定向html响应.
You should return 200 - OK, not 204 - No Content if you are returning the updated object, or don't return anything and have your client code 'GET' the updated object. :location is not meaningful in an api context, it's for redirecting an html response.
respond_with @account, status: :ok, responder: MyResponder
我自己还没有这样做,所以我不能举一个例子,但是无论如何这似乎有点过分.
I've not done this myself so I can't give an example, but it seems like overkill here anyway.
查看 Railscasts Episode:224 ,以获取对response_with的一些讨论,包括自定义响应者.
Check out Railscasts Episode:224 for some discussion of respond_with including custom responders.
这篇关于Rails中的PUT请求不会更新response_with调用的状态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!