11

レールに次のコントローラーがあるとします。

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

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 /アカウント/3d2cc5d0653911e2aaadc82a14fffee9
HTTP/1.1 204 コンテンツなし
場所: http://localhost:3000/api/accounts
X-Ua対応: IE=Edge
キャッシュ制御: キャッシュなし
X-Request-Id: bf0a02f452fbace65576aab6d2bd7c1e
X ランタイム: 0.029193
サーバー: WEBrick/1.3.1 (Ruby/1.9.3/2013-01-15)
日付: 2013 年 1 月 24 日 (木) 08:01:31 GMT
接続: 閉じる
セット Cookie: _bankshare_session=BAh7BkkiD3Nlc3Npb25faWQGOgZFRkkiJWFmNmI2MmU0MzViMmE3N2YzMDIzOTdjMDJmZDhiMzEwBjsAVA%3D%3D--133e394eb760a7fce07f1fd51349dc46c2d51626; パス=/; 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 が見つかりません
コンテンツ タイプ: アプリケーション/json; 文字セット=utf-8
X-Ua対応: IE=Edge
キャッシュ制御: キャッシュなし
X リクエスト ID: 9cc0d1cdfb27bb86a206cbc38cd75473
X ランタイム: 0.005118
サーバー: WEBrick/1.3.1 (Ruby/1.9.3/2013-01-15)
日付: 2013 年 1 月 24 日 (木) 08:19:45 GMT
コンテンツの長さ: 116
接続: キープアライブ

{"Friendly-status":"not-found","status":404,"message":"ID '3d2cc5d0653911e2aaadc82a14fffee9' のアカウントが見つかりません"}
4

3 に答える 3

4

この議論によると、このかなり非直感的な動作は、足場との互換性を維持したいという願望によるものです。

一般に、レスポンダーはスキャフォールドと同じ実装を維持します。これにより、respond_to を Respond_with に置き換えれば、すべてがまったく同じように機能します。

--ホセバリム

デフォルトの動作をオーバーライドするには、2 つの選択肢があります。

A) response_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 までの現在の推奨事項のようです。ここを参照してください。

更新されたオブジェクトを返す場合は204 - No Contentではなく200 - OKを返すか、何も返さずにクライアント コードで更新されたオブジェクトを「GET」する必要があります。:location は、API コンテキストでは意味がありません。html 応答をリダイレクトするためのものです。

B) カスタム レスポンダーを作成する

respond_with @account, status: :ok, responder: MyResponder

私はこれを自分でやったことがないので、例を挙げることはできませんが、とにかくここではやり過ぎのようです.

カスタム レスポンダーを含む Respond_with の議論については、Railscasts Episode:224を参照してください。

于 2013-09-21T05:30:26.837 に答える
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

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

ご覧のとおり、 api_behavior は post および get メソッドでは機能しますが、 put では機能しません。既存のリソースが変更された場合、リクエストが正常に完了したことを示すために、200 (OK) または 204 (コンテンツなし) の応答コードを送信する必要があります。

head :no_content はあなたが得るものです。

これは、レールが何をしようとしているのかを理解していないためです。この場合、Rails は、respond_with を使用してもエラーは発生しないと見なします (そのように使用してはならないバグではありません)。

必要なものだと思いrespond_toます。

于 2013-06-13T21:22:37.887 に答える