1. ホーム
  2. ruby-on-rails

[解決済み] Rails respond_with:どのように機能するのですか?

2022-06-13 11:59:13

質問

がいかにクールであるかということをあちこちで読んできました。 respond_with メソッドがRails 3でいかにクールであるかということをあちこちで読んできました。しかし、RailsのAPIでもソースを検索しても、このメソッドへの参照すら見つけることができません。どなたか、このメソッドがどのように機能するか (使用できるオプションなど) を説明してくれるか、または実際に実装されている場所を教えてくれて、自分でコードを精査できるようになりませんか?

どのように解決するのですか?

Rails 4.2+に対応するためのアップデート

#respond_with::respond_to ( n.b. クラスメソッド) は はもはやRailsの一部ではありません . これらはサードパーティの レスポンダ gemに移行されました ( リリースノート / コミット 2014年8月付け)。respondersはRailsにデフォルトで含まれていませんが、Deviseの依存関係にあるため、多くのRailsアプリケーションで利用可能です。

#respond_to インスタンスメソッドです。 しかし、このメソッドは はまだRailsの一部であり (この記事を書いている時点では5.2rc1)です。

の公式Rails APIドキュメントは ActionController::MimeResponds の説明では、どのように #respond_to がどのように機能するかを説明しています。オリジナルのRails Guidesドキュメントのコメントでは #respond_with::respond_to は、まだ レスポンダジェムのソースコード .


オリジナルの回答

レスポンダのコードはクラスとモジュールがベースになっています。 MimeResponds に含まれている ActionController::Base に含まれるクラス、つまり ApplicationController から継承しているクラスです。次に ActionController::Responder があり、これは respond_with を使用した場合のデフォルトの動作を提供します。


デフォルトでは、railsがレスポンスで提供する唯一の動作は、アクションに一致する名前を持つテンプレートをレンダリングする暗黙の試みです。それ以上の動作は、アクション内でさらに指示を出すか、複数の形式のレスポンスを処理するためのブロックを持つカスタムresponder_toコールが必要です。

ほとんどのコントローラでは、カスタマイズのパターンがかなり共通しているので、レスポンダはより多くのデフォルトの動作を導入することで、抽象化の特別なレベルを提供します。特定のフォーマットに対して to_xml/to_json を呼び出す読み込みアクションや、同じものを提供するミューテーターアクション、ミューテーターアクションが成功した場合のリダイレクトなどです。


レスポンダの動作をカスタマイズする機会がいくつかあり、微妙な調整から完全にオーバーライドまたは拡張することまでできます。

クラス レベル。 respond_to

レスポンダが処理するフォーマットを指定します。フォーマットは、どのアクションに適用するかカスタマイズすることができます。各フォーマットは別々の呼び出しで指定できるので、各フォーマットのアクションを完全にカスタマイズすることができます。

# Responds to html and json on all actions
respond_to :html, :json

# Responds to html and json on index and show actions only.
respond_to :html, :json, :only => [:index,:show]

# Responds to html for everything except show, and json only for index, create and update
respond_to :html, :except => [:show]
respond_to :json, :only => [:index, :create, :update]

クラスレベル responder

これはレスポンダを保持するクラス属性です。これは呼び出しに応答するものであれば何でもよく、つまり proc/lambda や呼び出しに応答するクラスを使用することができます。また、既存のメソッドをオーバーロードするために、既存のレスポンダに1つまたはモジュールをミックスして、デフォルトの動作を補強することもできます。

class SomeController < ApplicationController
  respond_to :json

  self.responder = proc do |controller, resources, options|
    resource = resources.last
    request = controller.request
    if request.get?
      controller.render json: resource
    elsif request.post? or request.put?
      if resource.errors.any?
        render json: {:status => 'failed', :errors => resource.errors}
      else
        render json: {:status => 'created', :object => resource}
      end
    end
  end
end

面白いエッジユース・ケースもあるかもしれませんが、デフォルトのレスポンダにモジュールを拡張したり混ぜたりする方がより一般的なパターンになりそうです。いずれにせよ、関連するオプションはリソースとオプションであり、それらはfrom respond_withから渡されるからです。

インスタンスレベル respond_with

ここでのオプションは、コントローラで render や redirect_to に渡されるものですが、これらは成功した場合のシナリオにのみ含まれています。GETアクションの場合はrenderの呼び出し、その他のアクションの場合はredirectのオプションになります。おそらくこれらのうち最も有用なのは :location オプションで、これは respond_with の引数が正しい URL を構築するのに十分でない場合に、リダイレクトパスを上書きするために使われます。

# These two are essentially equal
respond_with(:admin, @user, @post)
respond_with(@post, :location => admin_user_post(@user, @post)

# Respond with a 201 instead of a 200 HTTP status code, and also
# redirect to the collection path instead of the resource path
respond_with(@post, :status => :created, :location => posts_path)

# Note that if you want to pass a URL with a query string
# then the location option would be needed.
# /users?scope=active
respond_with(@user, :location => users_path(:scope => 'active'))


代替案として レスポンダー gem は、デフォルトの動作のいくつかをオーバーライドするためのモジュールを提供するだけではありません。デフォルトのレスポンダを拡張する無名クラスで上書きし、このクラスにカスタムモジュールを混ぜるためのクラスレベルのメソッドを提供します。ここで最も有用なのはフラッシュレスポンダで、デフォルトのフラッシュセットを提供し、カスタマイズをI18nシステムに委ねます。 config/locales/en.yml をデフォルトで使用します。

私が以前のプロジェクトで使用したカスタム レスポンダーの例には、リソースを自動的に装飾するレスポンダーや、ページ タイトルを簡単にカスタマイズしたり上書きしたりするためのインターフェイスを備えたデフォルトのページ タイトル セットを提供するレスポンダーがあります。