Rails中的PUT请求不会更新response_with调用的状态 [英] PUT requests in rails don't update the status on respond_with calls

查看:102
本文介绍了Rails中的PUT请求不会更新response_with调用的状态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给出以下导轨控制器:

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

  1. 如果id存在,并且update_attributes调用成功,则发送204 (No Content)成功消息. (我将它设置为返回@account,这很好,但没什么大不了的.这里的204很好.)
  2. 如果id存在,但是数据不正确,请提供422 (Unprocessable Entity)错误消息以及xml/json来表示错误.
  3. 如果id不存在,请提供404 (Not Found)错误消息以及xml/json来表示错误.
  1. 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.)
  2. 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.
  3. If the id does not exist, deliver a 404 (Not Found) error message, along with the xml/json to represent the error.

实际发生的是:

  1. 交付没有尸体的204.
  2. 交付没有尸体的204.
  3. 交付没有尸体的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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆