Rails:response_toブロックはどのように機能しますか?


210

私は通過つもりRailsの入門ガイドとセクション6.7と混同してしまいました。足場を生成した後、コントローラーで次の自動生成ブロックを見つけます。

def index
  @posts = Post.all

  respond_to do |format|
    format.html  # index.html.erb
    format.json  { render :json => @posts }
  end
end

response_toブロックが実際にどのように機能するかを理解したいと思います。フォーマットはどのタイプの変数ですか?.htmlおよび.jsonメソッドは、フォーマットオブジェクトですか?ドキュメントのための

ActionController::MimeResponds::ClassMethods::respond_to

質問に答えません。


ActionController :: MimeResponds :: ClassMethods :: respond_toのドキュメントにリンクできればいいのですが、api.rubyonrails.orgが直接ハイパーリンクを好まないようです...
Cole

respond_toは呼び出しの終了(例:blah.html、blah.jsonなど)を行い、指定されたビューと一致します。その他の応答は、XML、CSVなど、アプリケーションによって異なります。
ScottJShea

5
「指定されたビューとどのように一致しますか?」
Cole

拡張子(xml、htmlなど)がビューにマップされているとは思いません。デフォルトのレンダリング(format.html-引数なし)を選択した場合は、(URLおよびHTTP動詞に基づく)規則を使用して、ビュー(HTMLであると予想される)を選択します。レスポンダ(形式)は、ビューと規則を使用する代わりに、jsonでシリアル化することにより、.jsonで終わるURLをレンダリングするようにここで指示されています。
Craig Celeste

回答:


188

私はRubyが初めてで、この同じコードで行き詰まりました。私がハングアップした部分は、ここで見つけたいくつかの回答よりも少し基本的でした。これは誰かを助けるかもしれないし、しないかもしれません。

  • respond_toスーパークラスのメソッドActionControllerです。
  • それはデリゲートのようなブロックをとります。ブロックはfromからdoまでendであり|format|、ブロックへの引数として使用されます。
  • respond_toはブロックを実行し、format引数にResponderを渡します。

http://api.rubyonrails.org/v4.1/classes/ActionController/Responder.html

  • Responder以下のための方法を含んでいない.html.json、我々はとにかく、これらのメソッドを呼び出します!この部分は私にループを投げました。
  • Rubyにはと呼ばれる機能がありますmethod_missing。存在しないメソッド(jsonまたはなどhtml)を呼び出すと、Rubyはmethod_missing代わりにそのメソッドを呼び出します。

http://ruby-metaprogramming.rubylearning.com/html/ruby_metaprogramming_2.html

  • Responderクラスは、その使用をmethod_missing登録の一種として。「json」を呼び出すと、jsonにシリアル化することで、拡張子が.jsonのリクエストに応答するように指示します。html.htmlリクエストをデフォルトの方法で(慣習とビューを使用して)処理するように指示するには、引数なしで呼び出す必要があります。

次のように書くことができます(JSのような擬似コードを使用):

// get an instance to a responder from the base class
var format = get_responder()

// register html to render in the default way
// (by way of the views and conventions)
format.register('html')

// register json as well. the argument to .json is the second
// argument to method_missing ('json' is the first), which contains
// optional ways to configure the response. In this case, serialize as json.
format.register('json', renderOptions)

この部分は私を混乱させた。まだ直感的ではありません。Rubyはこのテクニックをかなり使用しているようです。クラス全体(responder)がメソッド実装になります。を活用するにmethod_missingは、クラスのインスタンスが必要なので、メソッドのようなオブジェクトを渡すコールバックを渡す必要があります。20年間Cのような言語でコーディングしてきた人にとって、これは非常に逆で、私には直感的ではありません。それは悪いことではありません!しかし、それはそのような背景を持つ多くの人々が頭を動かす必要があるものであり、私はOPが後にあったものだと思う。

PSはRoR 4.2 respond_toレスポンダーの宝石に抽出されたことに注意してください。


クレイグに感謝します。そのリンクには実際に大量の有用な情報がありました。method_missing引数ブロックを渡すことができることを考えると、でどれほどのことが可能かはわかりませんでした!
Aditya MP

2
method_missing()をResponderクラスの登録メカニズムとして使用する方法を説明する最良の回答です。私もこのコードに非常に混乱していました。
アランエヴァンジェリスタ

1
Rails 6の足場ジェネレータはrespond_to、Gemfileにレスポンダーgemが存在しない場合、コントローラーでコードを生成するようです。おそらくrespond_toレスポンダーの宝石に抽出されることについてのビットが変更されましたか?
カシム

106

これは、Railsヘルパーメソッドを利用するRubyコードのブロックです。まだブロックに慣れていない場合は、Rubyでよく見かけます。

respond_toは、コントローラクラス(または、そのスーパークラス)にアタッチされているRailsヘルパーメソッドです。ビュー(ブラウザーに送信される)に送信される応答を参照しています。

この例のブロックは、ブラウザがhtmlまたはjsonデータを要求するたびにコントローラーからビューに送信される、データのフォーマット(ブロックの「フォーマット」パラメーターを渡すことによる)です。

ローカルマシン上にあり、Postスキャフォールドを設定している場合は、そこに移動するhttp://localhost:3000/postsと、すべての投稿がHTML形式で表示されます。ただし、次のように入力 http://localhost:3000/posts.jsonすると、サーバーから送信されたjsonオブジェクトにすべての投稿が表示されます。

これは、サーバーとの間でjsonをやり取りする必要があるJavaScriptの重いアプリケーションを作成するのに非常に便利です。必要に応じて、Railsバックエンドにjson apiを簡単に作成し、Postコントローラーのインデックスビューのような1つのビューのみを渡すことができます。次に、JqueryBackbone(またはその両方)などのJavaScriptライブラリを使用して、データを操作し、独自のインターフェースを作成できます。これらは非同期UIと呼ばれ、非常に人気が高まっています(Gmailもその1つです)。それらは非常に高速で、エンドユーザーにWebでデスクトップのようなエクスペリエンスを提供します。もちろん、これはデータをフォーマットする利点の1つにすぎません。

これを書くRails 3の方法はこれだろう:

    class PostsController < ApplicationController
      # GET /posts
      # GET /posts.xml


      respond_to :html, :xml, :json

      def index
        @posts = Post.all

        respond_with(@posts)
      end

#
# All your other REST methods
#

end

respond_to :html, :xml, :jsonクラスの先頭に置くことで、コントローラーがビューに送信するすべてのフォーマットを宣言できます。

次に、コントローラメソッドでは、respond_with(@whatever_object_you_have)を実行するだけです。

Railsが自動生成するものよりもコードを単純化するだけです。

これの内部の仕組みについて知りたいなら ...

Railsは私が理解していることから、オブジェクトをイントロスペクトして、実際のフォーマットがどうなるかを判断します。'format'変数の値は、このイントロスペクションに基づいています。Railsは少しの情報で多くのことができます。単純な@postまたは:postがどこまで続くかに驚くでしょう。

たとえば、次のような_user.html.erb部分ファイルがあるとします。

_user.html.erb

<li>    
    <%= link_to user.name, user %>
</li>

次に、これを私のインデックスビューで単独で使用すると、「users」パーシャルを検索し、すべての「users」オブジェクトを反復処理する必要があることがRailsに通知されます。

index.html.erb

 <ul class="users">
   <%= render @users %>     
 </ul>

Railsに、 'user'パーシャルを見つけて、すべての 'users'オブジェクトを反復処理する必要があることを知らせます。

あなたはこのブログ投稿が役に立つと思うかもしれません:http : //archives.ryandaigle.com/articles/2009/8/6/what-s-new-in-edge-rails-cleaner-restful-controllers-w-respond_with

ソースを閲覧することもできますhttps : //github.com/rails/rails


1
rails3の方法についてのヒント。それでも、respond_toブロックの一番下に到達しようとしています。合格します。
Cole

4
良い答えですが、ブロックに渡されるフォーマット変数について具体的なことは何も言われていません。与えられた例では、format.htmlとformat.jsonがあります-これらの両方は、respond_toに渡されてから、respond_toがそれらの処理を決定しますか?
アンソニー

際だったrespond_torespond_with紹介?私はレール2.3.5を使用していますが、取得していますNoMethodError (undefined method respond_to)
14年

10

私が知っていることから、respond_toはActionControllerにアタッチされたメソッドであり、すべてのコントローラーでActionControllerを継承しているため、すべてのコントローラーで使用できます。Railsのrespond_toメソッドを次に示します。

def respond_to(&block)
  responder = Responder.new(self)
  block.call(responder)
  responder.respond
end

私がここに示すように、あなたはそれにブロックを渡しています:

respond_to <<**BEGINNING OF THE BLOCK**>> do |format|
  format.html
  format.xml  { render :xml => @whatever }
end <<**END OF THE BLOCK**>>

|フォーマット| partはブロックが期待している引数なので、respond_toメソッド内で使用できます。どうやって?

さて、あなたが気づいたら、respond_toメソッドで&を前に付けてブロックを渡し、そのブロックをProcとして扱うためにそれを行います。引数には「.xml」、「。html」があるため、呼び出すメソッドとして使用できます。

基本的に、respond_toクラスで行うのは、Responderクラスのインスタンスへのメソッド「.html、.xml、.json」の呼び出しです。


1
あなたが含めたソースとは異なるAPIドキュメントのrespond_toのソースは、私をスローダウンさせていました。スニペットを見ると、formatブロック引数がResponderオブジェクトに渡されていることがわかります。Responderのドキュメントが質問に答えて、今それを読んでいるようです。
Cole

7

私は、respond_toブロックが実際にどのように機能するかを理解したいと思います。フォーマットはどのタイプの変数ですか?.htmlおよび.jsonメソッドは、フォーマットオブジェクトですか?

何であるかを理解するためにformat、最初にのソースを見ることができますがrespond_to、すぐに実際に調べる必要があるのは、retrieve_response_from_mimesのコードであることがすぐにわかります

ここから、respond_to(コードで)に渡されたブロックが実際に呼び出され、Collectorのインスタンス(ブロック内ではとして参照されるformat)で渡されていることがわかります。Collectorは基本的に、Railsが知っているMIMEタイプに基づいてメソッドを生成します(私はRailsの起動時に信じています)。

したがって、はい、.htmlおよび.jsonは、コレクター(別名format)クラスで(実行時に)定義されるメソッドです。


2

レスポンダ登録の背後にあるメタプログラミング(Parched Squidの回答を参照)でも、次のような気の利いたことができます。

def index
  @posts = Post.all

  respond_to do |format|
    format.html  # index.html.erb
    format.json  { render :json => @posts }
    format.csv   { render :csv => @posts }
    format.js
  end
end

/posts.csvにアクセスすると、csv行によって各投稿でto_csvが呼び出されます。これにより、RailsサイトからデータをCSV(またはその他の形式)として簡単にエクスポートできます。

js行は、JavaScriptファイル/posts.js(または/posts.js.coffee)をレンダリング/実行します。私は、jQuery UIポップアップを使用してAjax対応サイトを作成する軽量な方法であることがわかりました。


1

フォーマットはどのタイプの変数ですか?

Java POVのフォーマットは、匿名インターフェースの実装です。このインターフェースには、MIMEタイプごとに名前が付けられた1つのメソッドがあります。これらのメソッドの1つを呼び出す(ブロックを渡す)と、ユーザーがそのコンテンツタイプを望んでいるとRailsが感じた場合は、ブロックを呼び出します。

もちろん、ひねりは、この匿名の接着剤オブジェクトが実際にインターフェースを実装していないことです。動的にメソッド呼び出しをキャッチし、それが知っているMIMEタイプの名前である場合はうまくいきます。

個人的には、奇妙に見えます。渡したブロックが実行されます。フォーマットラベルとブロックのハッシュを渡すことは、私にはより理にかなっています。しかし、それがRoRでのやり方です。


1

これは少し時代遅れです。RyanBiggがここでこれを説明する素晴らしい仕事をしています:

http://ryanbigg.com/2009/04/how-rails-works-2-mime-types-respond_to

実際、あなたが探していたよりも少し詳細かもしれません。結局のところ、MIMEタイプがどのようにロードされるかを理解する必要があるなど、裏で多くのことが行われています。



0

知っておくべきことがもう1つあります-MIMEです。

MIMEタイプを使用する必要があり、それがデフォルトでサポートされていない場合は、config / initializers / mime_types.rbに独自のハンドラーを登録できます。

Mime::Type.register "text/markdown", :markdown

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.