2012-02-29 30 views
183

Tôi đang xem qua hướng dẫn Getting Started with 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 đây trong bộ điều khiển của tôi:Đường ray: Cách respond_to chặn hoạt động?

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 cách khối phản hồi thực sự hoạt động. Loại biến nào là định dạng? Các phương thức .html và .json của đối tượng định dạng? Các documentation cho ActionController::MimeResponds::ClassMethods::respond_to không trả lời câu hỏi.

+0

Sẽ rất tuyệt nếu tôi có thể liên kết đến tài liệu cho ActionController :: MimeResponds :: ClassMethods :: respond_to nhưng api.rubyonrails.org không xuất hiện như các siêu liên kết trực tiếp ... – Cole

+0

respond_to sẽ 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 câu trả lời khác có thể là XML, CSV và nhiều ứng dụng khác tùy thuộc vào ứng dụng. – ScottJShea

+4

Làm cách nào để "khớp với chế độ xem được chỉ định?" – Cole

Trả lời

95

Đây là một khối mã Ruby sử dụng phương thức 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_to là phương thức trợ giúp Rails được đính kèm với lớp Bộ điều khiển (hoặc đúng hơn là lớp siêu của nó). Nó đang tham chiếu câu trả lời sẽ được gửi đến View (sắp tới trình duyệt).

Khối trong ví dụ của bạn là dữ liệu định dạng - bằng cách truyền thông 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 yêu cầu dữ liệu html hoặc json.

Nếu bạn đang ở trên máy địa phương và bạn đã thiết lập giàn giáo, bạn có thể truy cập http://localhost:3000/posts và bạn sẽ thấy tất cả các bài đăng của mình ở định dạng html. Tuy nhiên, nếu bạn nhập vào: 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 tiện lợi cho việc tạo các ứng dụng javascript nặng 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 ra một api json trên đường ray của bạn back-end, và chỉ truyền một khung nhìn - giống như khung nhìn chỉ mục của bộ đ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 đang trở nên phổ biến (Gmail là một). Chúng rất nhanh và cung cấp cho người dùng cuối trải nghiệm giống như trên máy tính để bà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ác Rails 3 cách viết này sẽ là:

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 ở phía trên cùng của lớp, bạn có thể khai báo tất cả các định dạng mà bạn muốn điều khiển của bạn để gửi đến quan điểm của bạn.

Sau đó, trong phương pháp điều khiển, tất cả các bạn phải làm là respond_with (@whatever_object_you_have)

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

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

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

Ví dụ, nếu tôi đã có một tập tin cục bộ _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 theo quan điểm của tôi chỉ số sẽ cho phép Rails biết rằng nó cần thiết để tìm ra 'người sử dụng một phần 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 phép Rails biết rằng nó cần thiết để tìm ra 'người sử dụng' một phần và lặp qua tất cả các đối tượng của người dùng ':

Bạn có thể tìm thấy bài đăng blog 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 nội dung các nguồn: https://github.com/rails/rails

+1

Mẹo hay trên đường ray3. Tôi vẫn đang cố gắng đến cuối khối respond_to, và đối số khối | định dạng | được thông qua. – Cole

+3

Câu trả lời hay nhưng không nói bất cứ điều gì cụ thể về biến định dạng được chuyển vào khối. Trong ví dụ được cung cấp có format.html và format.json - cả hai đều được chuyển đến response_to và sau đó respond_to quyết định phải làm gì với chúng? – Anthony

+0

khi nào 'response_to' và' respond_with' được giới thiệu? Tôi đang sử dụng ** đường ray 2.3.5 ** và tôi nhận được 'NoMethodError (phương thức undefined_to)' – abbood

9

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

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

Bạn đang đi qua nó một block, như tôi thấy ở đâ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 chờ đợi, vì vậy bên trong phương thức respond_to chúng ta có thể sử dụng nó. Làm sao?

Vâng, 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 respond_to và chúng tôi thực hiện điều đó để coi khối đó là Proc. Vì đối số có ".xml", ".html", chúng ta có thể sử dụng nó làm phương thức để gọi.

Điều chúng ta làm cơ bản trong lớp respond_to là các phương thức gọi là ".html, .xml, .json" đối với một thể hiện của lớp Responder.

+1

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

7

Tôi muốn hiểu cách khối phản hồi thực sự hoạt động. Loại biến số nào là định dạng? Các phương thức .html và .json có định dạng là đối tượng không?

Để hiểu những gì format là, trước tiên bạn có thể nhìn vào các nguồn cho respond_to, nhưng nhanh chóng bạn sẽ thấy rằng những gì thực sự bạn cần phải nhìn vào là mã cho retrieve_response_from_mimes.

Từ đây, bạn sẽ thấy khối đã được chuyển đến respond_to (trong mã của bạn), thực sự được gọi và được chuyển với một phiên bản 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 vào Rails start-up) dựa trên những gì mà đường ray mime types biết.

Vì vậy, có, .html.json là các phương thức được xác định (khi chạy) trên lớp Collector (aka format).

0

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

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

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

158

Tôi mới dùng Ruby và bị kẹt ở cùng mã này. Các bộ phận mà tôi đã treo lên trên 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à phương thức trên siêu lớp ActionController.
  • phải mất một khối, giống như một đại biểu. Khối này là từ do cho đến end, với |format| làm đối số cho khối.
  • respond_to thực thi khối của bạn, chuyển Responder vào đối số format.

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

  • Các Responder KHÔNG chứa một phương pháp để .html hoặc .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ư json hoặc html), Ruby sẽ gọi phương thức method_missing.

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

  • Lớp Responder sử dụng của nó method_missing như một loại đăng ký. Khi chúng ta gọi 'json', chúng ta đang yêu cầu nó trả lời các yêu cầu với phần mở rộng .json bằng cách tuần tự hóa thành json. Chúng ta cần gọi html mà không có đối số nào để 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à khung nhìn).

Nó có thể được viết như thế này (sử dụng JS giống như giả):

// 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 nhầm lẫn các heck ra khỏi tôi. Tôi vẫn thấy nó không trực quan. Ruby có vẻ sử dụng kỹ thuật này một chút. Toàn bộ lớp học (responder) trở thành triển khai phương pháp. Để tận dụng method_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 chuyển một cuộc gọi lại vào đó 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 ngôn ngữ C giống như trong 20 năm, điều này rất lạc hậu và không trực quan đối với tôi. Không phải là nó xấu! Nhưng đó là điều mà nhiều người có nền tảng như vậy cần phải xoay sở, và tôi nghĩ có thể đó là những gì mà OP đã làm.

p.s. lưu ý rằng trong RoR 4,2 respond_to được chiết xuất thành responders đá quý.

+0

tôi hoàn toàn đồng ý, nguồn ruby ​​khó đọc. –

+0

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

2

meta-lập trình đằng sau đăng ký trả lời (xem câu trả lời khô cằn của Squid) cũng cho phép bạn để làm công cụ 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ẽ gây to_csv được gọi trên mỗi bài 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 đường ray của bạn.

Dòng js sẽ làm cho 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ẹ cân để tạo một trang web được kích hoạt Ajax bằng cách sử dụng cửa sổ bật lên jQuery UI.

1

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

Từ java POV, định dạng là sự triển khai 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 những phương thức đó (chuyể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, sự thay đổi này là đối tượng keo ẩn danh này không thực sự thực hiện một giao diện - nó bắt phương thức gọi tự động và làm việc nếu tên của nó là loại mime mà nó biết.

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

0

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

Các vấn đề liên quan