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,location: accounts_url end end def error_hash { :example => "Example for this question",:parameter => 42 } end end
我会期望一个PUT请求/ accounts / update /来执行以下操作
>如果id存在,并且update_attributes调用成功,则提供204(无内容)成功消息. (我有它返回@account,这将是不错的,但没有什么大不了的204在这里很好)
>如果id存在但数据不正确,则会传递一个422(Unprocessible Entity)错误消息以及xml / json来表示错误.
>如果id不存在,请传送404(Not Found)错误消息以及xml / json以表示错误.
实际发生的是:
提供一个没有身体的204.
提供一个没有身体的204.
提供一个没有身体的204.
为什么它忽略了我的身份和身体?我已经有一个类似的设置GET请求,工作很好(正确的状态,正确的身体).
示例CURL请求(对于不存在的ID):
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"}
解决方法
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
您有两个选择来覆盖默认行为.
A)将一个块传递给respond_with
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的当前建议;见here.
如果您返回更新的对象,或者不返回任何东西并让您的客户端代码“GET”更新的对象,则应返回200 – OK,而不是204 – 否. :位置在api上下文中无意义,它用于重定向html响应.
B)创建一个自定义响应者
respond_with @account,status: :ok,responder: MyResponder
我自己也没有这样做,所以我不能举个例子,但是这似乎也是过分的.
查看Railscasts Episode:224有关response_with的一些讨论,包括自定义响应者.