IT story

Rails : respond_to 블록은 어떻게 작동합니까?

hot-time 2020. 5. 6. 21:06
반응형

Rails : respond_to 블록은 어떻게 작동합니까?


나는이를 통해 갈거야 레일스 시작하기 가이드 및 6.7와 혼동되었다. 스캐 폴드를 생성 한 후 컨트롤러에서 다음과 같은 자동 생성 블록을 찾습니다.

def index
  @posts = Post.all

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

respond_to 블록이 실제로 어떻게 작동하는지 이해하고 싶습니다. 어떤 유형의 변수가 형식입니까? 형식 객체의 .html 및 .json 메소드입니까? 문서 에 대한이 ActionController::MimeResponds::ClassMethods::respond_to질문에 대답하지 않습니다.


저는 Ruby를 처음 사용하고 동일한 코드를 고수했습니다. 내가 끊었던 부분은 내가 찾은 답변보다 약간 더 근본적이었습니다. 이것은 누군가를 도울 수도 아닐 수도 있습니다.

  • respond_to수퍼 클래스의 메소드입니다 ActionController.
  • 델리게이트와 같은 블록이 필요합니다. 블록은 do까지 의 인수로 end, 까지 |format|입니다.
  • respond_to는 블록에 응답자를 전달하여 블록을 실행합니다 format.

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)

이 부분은 도대체 나를 혼란스럽게했다. 여전히 직관적이지 않습니다. 루비는이 기술을 꽤 많이 사용하는 것 같습니다. 전체 클래스 ( responder)가 메소드 구현이됩니다. 를 활용 method_missing하려면 클래스의 인스턴스가 필요하므로 메소드와 유사한 객체를 전달하는 콜백을 전달해야합니다. 20 년 동안 C와 같은 언어로 코딩 한 사람에게는 이것이 매우 역행적이고 직관적이지 않습니다. 나쁘지 않아! 그러나 그것은 그런 종류의 배경을 가진 많은 사람들이 고개를 숙여 야 할 필요가 있습니다.

ps는 RoR 4.2 respond_to에서 응답자 gem 으로 추출되었습니다 .


이것은 Rails 헬퍼 메소드를 이용하는 Ruby 코드 블록입니다. 아직 블록에 익숙하지 않다면 Ruby에서 블록을 많이 볼 수 있습니다.

respond_toController 클래스 (또는 상위 클래스)에 첨부 된 Rails 헬퍼 메소드입니다. View로 전송 될 응답 (브라우저로 이동)을 참조합니다.

귀하의 예제에서 블록은 브라우저가 html 또는 json 데이터를 요청할 때마다 컨트롤러에서보기로 전송되도록 블록의 '형식'매개 변수를 전달하여 데이터를 형식화하는 것입니다.

로컬 컴퓨터에 있고 Post 비계를 설정 한 경우을 방문하여 http://localhost:3000/posts모든 게시물을 html 형식으로 볼 수 있습니다. 그러나 다음을 입력 http://localhost:3000/posts.json하면 서버에서 보낸 json 객체에 모든 게시물이 표시됩니다.

This is very handy for making javascript heavy applications that need to pass json back and forth from the server. If you wanted, you could easily create a json api on your rails back-end, and only pass one view - like the index view of your Post controller. Then you could use a javascript library like Jquery or Backbone (or both) to manipulate data and create your own interface. These are called asynchronous UIs and they are becomming really popular (Gmail is one). They are very fast and give the end-user a more desktop-like experience on the web. Of course, this is just one advantage of formatting your data.

The Rails 3 way of writing this would be this:

    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

By putting respond_to :html, :xml, :json at the top of the class, you can declare all the formats that you want your controller to send to your views.

Then, in the controller method, all you have to do is respond_with(@whatever_object_you_have)

It just simplifies your code a little more than what Rails auto-generates.

If you want to know about the inner-workings of this...

From what I understand, Rails introspects the objects to determine what the actual format is going to be. The 'format' variables value is based on this introspection. Rails can do a whole lot with a little bit of info. You'd be surprised at how far a simple @post or :post will go.

For example, if I had a _user.html.erb partial file that looked like this:

_user.html.erb

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

Then, this alone in my index view would let Rails know that it needed to find the 'users' partial and iterate through all of the 'users' objects:

index.html.erb

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

would let Rails know that it needed to find the 'user' partial and iterate through all of the 'users' objects:

You may find this blog post useful: http://archives.ryandaigle.com/articles/2009/8/6/what-s-new-in-edge-rails-cleaner-restful-controllers-w-respond_with

You can also peruse the source: https://github.com/rails/rails


From what I know, respond_to is a method attached to the ActionController, so you can use it in every single controller, because all of them inherits from the ActionController. Here is the Rails respond_to method:

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

You are passing it a block, like I show here:

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

The |format| part is the argument that the block is expecting, so inside the respond_to method we can use that. How?

Well, if you notice we pass the block with a prefixed & in the respond_to method, and we do that to treat that block as a Proc. Since the argument has the ".xml", ".html" we can use that as methods to be called.

What we basically do in the respond_to class is call methods ".html, .xml, .json" to an instance of a Responder class.


I'd like to understand how the respond_to block actually works. What type of variable is format? Are .html and .json methods of the format object?

In order to understand what format is, you could first look at the source for respond_to, but quickly you'll find that what really you need to look at is the code for retrieve_response_from_mimes.

From here, you'll see that the block that was passed to respond_to (in your code), is actually called and passed with an instance of Collector (which within the block is referenced as format). Collector basically generates methods (I believe at Rails start-up) based on what mime types rails knows about.

So, yes, the .html and .json are methods defined (at runtime) on the Collector (aka format) class.


The meta-programming behind responder registration (see Parched Squid's answer) also allows you to do nifty stuff like this:

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

The csv line will cause to_csv to be called on each post when you visit /posts.csv. This makes it easy to export data as CSV (or any other format) from your rails site.

The js line will cause a javascript file /posts.js (or /posts.js.coffee) to be rendered/executed. I've found that to be a light-weight way to create an Ajax enabled site using jQuery UI pop-ups.


This is a little outdated, by Ryan Bigg does a great job explaining this here:

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

In fact, it might be a bit more detail than you were looking for. As it turns out, there's a lot going on behind the scenes, including a need to understand how the MIME types get loaded.


What type of variable is format?

From a java POV, format is an implemtation of an anonymous interface. This interface has one method named for each mime type. When you invoke one of those methods (passing it a block), then if rails feels that the user wants that content type, then it will invoke your block.

The twist, of course, is that this anonymous glue object doesn't actually implement an interface - it catches the method calls dynamically and works out if its the name of a mime type that it knows about.

Personally, I think it looks weird: the block that you pass in is executed. It would make more sense to me to pass in a hash of format labels and blocks. But - that's how its done in RoR, it seems.


There is one more thing you should be aware of - MIME.

If you need to use a MIME type and it isn't supported by default, you can register your own handlers in config/initializers/mime_types.rb:

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


"Format" is your response type. Could be json or html, for example. It's the format of the output your visitor will receive.

참고URL : https://stackoverflow.com/questions/9492362/rails-how-does-the-respond-to-block-work

반응형