Rails: Khối answer_to hoạt động như thế nào?


210

Tôi đang trải qua hướng dẫn Bắt đầu với Rails và bị nhầm lẫn với phần 6.7. Sau khi tạo một giàn giáo, tôi tìm thấy khối được tạo tự động sau trong bộ điều khiển của mình:

def index
  @posts = Post.all

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

Tôi muốn hiểu làm thế nào khối answer_to thực sự hoạt động. Loại biến nào là định dạng? Là các phương thức .html và .json của đối tượng định dạng? các tài liệu hướng dẫn cho

ActionController::MimeResponds::ClassMethods::respond_to

không trả lời câu hỏi.


Sẽ thật tuyệt nếu tôi có thể liên kết đến tài liệu cho ActionContoder :: MimeR tương ứng :: ClassMethods :: respons_to nhưng api.rubyonrails.org dường như không thích siêu liên kết trực tiếp ...
Cole

answer_to kết thúc cuộc gọi (ví dụ: blah.html, blah.json, v.v.) và khớp với chế độ xem được chỉ định. Các phản hồi khác có thể là XML, CSV và nhiều thứ khác tùy thuộc vào ứng dụng.
ScottJShea

5
Làm thế nào để nó "phù hợp với quan điểm được chỉ định?"
Cole

Tôi không nghĩ rằng phần mở rộng (xml, html, v.v.) ánh xạ tới một khung nhìn. Nếu bạn chọn kết xuất mặc định ( format.html- không có đối số), nó sẽ sử dụng các quy ước (dựa trên động từ URL và HTTP) để chọn chế độ xem (dự kiến ​​là HTML). Phản hồi (định dạng) được hướng dẫn ở đây để hiển thị các URL kết thúc bằng .json bằng cách tuần tự hóa thành json, thay vì sử dụng các chế độ xem và quy ước.
Craig Celeste

Câu trả lời:


188

Tôi mới biết về Ruby và bị mắc kẹt ở cùng mã này. Những phần mà tôi đã gác máy là một chút cơ bản hơn một số câu trả lời tôi tìm thấy ở đây. Điều này có thể hoặc không thể giúp đỡ ai đó.

  • respond_to là một phương pháp trên siêu lớp ActionController .
  • nó có một khối, giống như một đại biểu. Khối là từ docho đếnend , với |format|tư cách là một đối số cho khối.
  • answer_to thực thi khối của bạn, chuyển Phản hồi vào format đối số.

http://api.rubyonrails.org/v4.1/groupes/ActionControll/Responder.html

  • Các ResponderKHÔNG chứa một phương pháp để.html hay.json , nhưng chúng ta gọi là những phương pháp anyways! Phần này đã ném tôi cho một vòng lặp.
  • Ruby có một tính năng được gọi là method_missing. Nếu bạn gọi một phương thức không tồn tại (như jsonhoặc html), method_missingthay vào đó , Ruby gọi phương thức đó.

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

  • Các Responderlớp sử dụng nó method_missingnhư là một loại đăng ký. Khi chúng tôi gọi 'json', chúng tôi sẽ bảo nó trả lời các yêu cầu có phần mở rộng .json bằng cách nối tiếp với json. Chúng ta cần gọi htmlmà không có đối số để yêu cầu nó xử lý các yêu cầu .html theo cách mặc định (sử dụng các quy ước và chế độ xem).

Nó có thể được viết như thế này (sử dụng mã giả giống như 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)

Phần này làm tôi bối rối. Tôi vẫn thấy nó không trực quan. Ruby dường như sử dụng kỹ thuật này khá nhiều. Toàn bộ lớp ( responder) trở thành phương thức thực hiện. Để tận dụngmethod_missing , chúng ta cần một thể hiện của lớp, vì vậy chúng ta bắt buộc phải truyền lại một cuộc gọi lại để chúng truyền đối tượng giống như phương thức. Đối với một người đã mã hóa bằng các ngôn ngữ giống như C trong 20 năm, điều này rất ngược và không trực quan với tôi. Không tệ đâu! Nhưng đó là điều mà rất nhiều người có nền tảng đó cần phải có được, và tôi nghĩ có thể đó là những gì OP đã làm sau đó.

ps lưu ý rằng trong RoR 4.2 respond_tođã được trích xuất thành đá quý đáp ứng .


Cảm ơn Craig, liên kết đó thực sự cũng có rất nhiều thông tin hữu ích, tôi không nhận ra có thể có bao nhiêu với method_missingviệc xem xét bạn có thể vượt qua các đối số một khối!
MP Aditya

2
Câu trả lời tốt nhất để giải thích việc sử dụng phương thức_missing () làm cơ chế đăng ký trong lớp Phản hồi! Tôi cũng rất bối rối với mã này.
Alan Evangelista

1
Các bộ tạo giàn giáo Rails 6 dường như tạo ra mã với respond_tocác bộ điều khiển, không có đá quý đáp ứng có trong Gemfile. Có lẽ một chút về việc respond_tođược trích xuất vào đá quý người trả lời, đã được thay đổi?
Qasim

106

Đây là một khối mã Ruby tận dụng phương thức của trình trợ giúp Rails. Nếu bạn chưa quen với các khối, bạn sẽ thấy chúng rất nhiều trong Ruby.

respond_tolà một phương thức của trình trợ giúp Rails được gắn vào lớp Trình điều khiển (hay đúng hơn là siêu lớp của nó). Đó là tham chiếu phản hồi sẽ được gửi tới Chế độ xem (sẽ đến trình duyệt).

Khối trong ví dụ của bạn là định dạng dữ liệu - bằng cách chuyển vào tham số 'định dạng' trong khối - để được gửi từ bộ điều khiển đến chế độ xem bất cứ khi nào trình duyệt đưa ra yêu cầu về dữ liệu html hoặc json.

Nếu bạn đang ở trên máy cục bộ của mình và bạn đã cài đặt giàn giáo Post, bạn có thể truy cập http://localhost:3000/postsvà bạn sẽ thấy tất cả các bài đăng của mình ở định dạng html. Nhưng, nếu bạn nhập vào đây : http://localhost:3000/posts.json, thì bạn sẽ thấy tất cả các bài đăng của mình trong một đối tượng json được gửi từ máy chủ.

Điều này rất thuận tiện để tạo các ứng dụng nặng javascript cần truyền json qua lại từ máy chủ. Nếu bạn muốn, bạn có thể dễ dàng tạo một api json trên back-end của bạn và chỉ vượt qua một chế độ xem - như chế độ xem chỉ mục của trình điều khiển Post của bạn. Sau đó, bạn có thể sử dụng thư viện javascript như Jquery hoặc Backbone (hoặc cả hai) để thao tác dữ liệu và tạo giao diện của riêng bạn. Chúng được gọi là UI không đồng bộ và chúng thực sự phổ biến (Gmail là một). Chúng rất nhanh và mang lại cho người dùng cuối trải nghiệm giống như máy tính để bàn hơn trên web. Tất nhiên, đây chỉ là một lợi thế của việc định dạng dữ liệu của bạn.

Cách viết của Rails 3 sẽ là thế này:

    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

Bằng cách đặt respond_to :html, :xml, :json ở đầu lớp, bạn có thể khai báo tất cả các định dạng mà bạn muốn trình điều khiển gửi đến các khung nhìn của mình.

Sau đó, trong phương thức của bộ điều khiển, tất cả những gì bạn phải làm là respons_with (@whthing_object_you_have)

Nó chỉ đơn giản hóa mã của bạn nhiều hơn một chút so với những gì Rails tự động tạo.

Nếu bạn muốn biết về hoạt động bên trong của ...

Từ những gì tôi hiểu, Rails hướng nội các đối tượng để xác định định dạng thực tế sẽ là gì. Giá trị biến 'định dạng' dựa trên nội quan này. Rails có thể làm rất nhiều với một chút thông tin. Bạn sẽ ngạc nhiên khi một bài đăng @post hoặc: đơn giản sẽ đi được bao xa.

Ví dụ: nếu tôi có tệp một phần _user.html.erb trông như thế này:

_user.html.erb

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

Sau đó, điều này một mình trong chế độ xem chỉ mục của tôi sẽ cho Rails biết rằng cần phải tìm một phần 'người dùng' và lặp qua tất cả các đối tượng của 'người dùng':

index.html.erb

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

sẽ cho Rails biết rằng cần phải tìm một phần 'người dùng' và lặp qua tất cả các đối tượng của 'người dùng':

Bạn có thể thấy bài đăng trên blog này hữu ích: http://archives.ryandaigle.com/articles/2009/8/6/what-s-new-in-edge-rails-cleaner-restful-controllers-w-respond_with

Bạn cũng có thể kiểm tra nguồn: https://github.com/rails/rails


1
Mẹo hay trên đường ray3. Tôi vẫn đang cố gắng tìm hiểu phần cuối của khối answer_to và đối số khối | định dạng | được thông qua.
Cole

4
Câu trả lời hay nhưng không nói gì cụ thể về biến định dạng được truyền vào khối. Trong ví dụ đưa ra có format.html và format.json - cả hai điều này có được truyền cho respons_to và sau đó answer_to quyết định làm gì với chúng không?
Anthony

Khi nào respond_tovà được respond_withgiới thiệu? Tôi đang sử dụng đường ray 2.3.5 và tôi đang nhận đượcNoMethodError (undefined method respond_to)
abbood 21/03 '

10

Từ những gì tôi biết, respons_to là một phương thức được gắn vào ActionContoder, vì vậy bạn có thể sử dụng nó trong mọi bộ điều khiển duy nhất, bởi vì tất cả chúng đều kế thừa từ ActionContoder. Đây là phương thức Rails respons_to:

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

Bạn đang vượt qua nó một khối , như tôi chỉ ra ở đây:

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

Các | format | một phần là đối số mà khối đang mong đợi, vì vậy bên trong phương thức respons_to chúng ta có thể sử dụng nó. Làm sao?

Chà, nếu bạn nhận thấy chúng tôi vượt qua khối có tiền tố & trong phương thức respons_to và chúng tôi làm điều đó để coi khối đó là Proc. Vì đối số có ".xml", ".html", chúng ta có thể sử dụng đó làm phương thức được gọi.

Những gì chúng ta cơ bản làm trong lớp respons_to là các phương thức gọi ".html, .xml, .json" cho một thể hiện của lớp Phản hồi.


1
Nguồn cho answer_to trong tài liệu api khác với nguồn bạn đưa vào và đã làm tôi thất vọng. Đoạn mã của bạn làm cho tôi rõ ràng hơn rằng đối số khối định dạng đang được thông qua một đối tượng Phản hồi. Tài liệu Phản hồi dường như trả lời câu hỏi, đọc nó ngay bây giờ.
Cole

7

Tôi muốn hiểu làm thế nào khối answer_to thực sự hoạt động. Loại biến nào là định dạng? Là các phương thức .html và .json của đối tượng định dạng?

Để hiểu được đó formatlà gì , trước tiên bạn có thể xem nguồn respond_to, nhưng nhanh chóng bạn sẽ thấy rằng thứ bạn thực sự cần xem là mã cho lấy_response_from_mimes .

Từ đây, bạn sẽ thấy rằng khối được truyền đến respond_to(trong mã của bạn), thực sự được gọi và được truyền với một thể hiện của Collector (trong khối được tham chiếu là format). Collector về cơ bản tạo ra các phương thức (tôi tin tại Rails start-up) dựa trên những gì mime loại rails biết về.

Vì vậy, vâng, .html.jsonlà các phương thức được định nghĩa (trong thời gian chạy) trên lớp Collector (aka format).


2

Lập trình meta đằng sau đăng ký trả lời (xem câu trả lời của Parched Squid) cũng cho phép bạn thực hiện những thứ tiện lợi như thế này:

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

Dòng csv sẽ khiến to_csv được gọi trên mỗi bài đăng khi bạn truy cập /posts.csv. Điều này giúp dễ dàng xuất dữ liệu dưới dạng CSV (hoặc bất kỳ định dạng nào khác) từ trang web rails của bạn.

Dòng js sẽ khiến tệp javascript /posts.js (hoặc /posts.js.coffee) được hiển thị / thực thi. Tôi đã thấy rằng đó là một cách nhẹ nhàng để tạo một trang web hỗ trợ Ajax bằng cách sử dụng cửa sổ bật lên UI UI.


1

Loại biến nào là định dạng?

Từ java POV, định dạng là một hình ảnh của giao diện ẩn danh. Giao diện này có một phương thức được đặt tên cho từng loại mime. Khi bạn gọi một trong các phương thức đó (truyền cho nó một khối), thì nếu đường ray cảm thấy rằng người dùng muốn loại nội dung đó, thì nó sẽ gọi khối của bạn.

Tất nhiên, vấn đề khó khăn là đối tượng keo ẩn danh này không thực sự thực hiện giao diện - nó bắt phương thức gọi một cách linh hoạt và tìm ra nếu đó là tên của một loại mime mà nó biết.

Cá nhân, tôi nghĩ nó có vẻ kỳ lạ: khối mà bạn vượt qua được thực thi . Nó sẽ có ý nghĩa hơn đối với tôi để vượt qua một hàm băm của các nhãn và khối định dạng. Nhưng - đó là cách nó được thực hiện trong RoR, dường như.


1

Đây là một chút lỗi thời, bởi Ryan Bigg thực hiện một công việc tuyệt vời giải thích điều này ở đây:

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

Trong thực tế, nó có thể là một chút chi tiết hơn bạn đang tìm kiếm. Hóa ra, có rất nhiều điều đang diễn ra đằng sau hậu trường, bao gồm nhu cầu hiểu cách các loại MIME được tải.


0

"Định dạng" là loại phản hồi của bạn. Có thể là json hoặc html chẳng hạn. Đó là định dạng của đầu ra mà khách truy cập của bạn sẽ nhận được.


0

Có một điều nữa bạn nên chú ý - MIME.

Nếu bạn cần sử dụng loại MIME và mặc định nó không được hỗ trợ, bạn có thể đăng ký trình xử lý của riêng mình trong config / khởi tạo / mime_types.rb:

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.