rails中的PUT请求不会更新respond_with调用的状态

ash*_*ays 11 json ruby-on-rails

在rails中给出以下控制器:

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
Run Code Online (Sandbox Code Playgroud)

我希望PUT对/ accounts/update/的请求执行以下操作

  1. 如果id存在,并且update_attributes调用成功,则传递204 (No Content)成功消息.(我已经将它设置为返回@account,这将是不错的,但没什么大不了的.这里的204很好.)
  2. 如果id存在但数据不正确,则提供422 (Unprocessable Entity)错误消息以及xml/json以表示错误.
  3. 如果id不存在,则传递404 (Not Found)错误消息以及xml/json以表示错误.

实际发生的是:

  1. 交付204没有身体.
  2. 交付204没有身体.
  3. 交付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"}

Fiv*_*ell 3

你看到 ActionController::Responder 类了吗?这里有一些值得思考的方法

 # All other formats follow the procedure below. First we try to render a
    # template, if the template is not available, we verify if the resource
    # responds to :to_format and display it.
    #
    def to_format
      if get? || !has_errors? || response_overridden?
        default_render
      else
        display_errors
      end
    rescue ActionView::MissingTemplate => e
      api_behavior(e)
    end
Run Code Online (Sandbox Code Playgroud)

def api_behavior(error)
      raise error unless resourceful?

      if get?
        display resource
      elsif post?
        display resource, :status => :created, :location => api_location
      else
        head :no_content
      end
    end
Run Code Online (Sandbox Code Playgroud)

正如您所看到的, api_behavior 适用于 post 和 get 方法,但不适用于 put 。如果现有资源被修改,则应发送 200(OK)或 204(无内容)响应代码以指示请求成功完成。

head :no_content 就是你得到的。

所以原因是 Rails 不明白你想做什么。Rails 认为在这种情况下使用 respond_with 时没有错误。(这不是一个错误,你只是不应该那样使用它)

我想respond_to这就是你所需要的。