ทางรถไฟ: การตอบสนองต่อการบล็อกทำงานอย่างไร


211

ฉันกำลังอ่านคู่มือการเริ่มต้นใช้งาน Railsและสับสนกับหัวข้อ 6.7 หลังจากสร้างโครงสร้างขึ้นฉันพบบล็อกที่สร้างขึ้นอัตโนมัติในคอนโทรลเลอร์ของฉัน:

def index
  @posts = Post.all

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

ฉันต้องการที่จะเข้าใจว่าการตอบสนองการปิดกั้นการทำงานจริง รูปแบบของตัวแปรชนิดใด .html และ. json เป็นวิธีการจัดรูปแบบวัตถุหรือไม่ เอกสารสำหรับ

ActionController::MimeResponds::ClassMethods::respond_to

ไม่ตอบคำถาม


มันจะดีถ้าฉันสามารถเชื่อมโยงไปยังเอกสารสำหรับ ActionController :: MimeResponds :: ClassMethods :: respond_to แต่ api.rubyonrails.org ไม่ปรากฏเช่นการเชื่อมโยงโดยตรง ...
โคล

respons_to จะสิ้นสุดการโทร (เช่น blah.html, blah.json ฯลฯ ) และตรงกับมุมมองที่ระบุ การตอบสนองอื่น ๆ อาจเป็น XML, CSV และอื่น ๆ อีกมากมายขึ้นอยู่กับแอปพลิเคชัน
ScottJShea

5
"จับคู่มุมมองที่ระบุอย่างไร"
โคล

ฉันไม่คิดว่าแผนที่ส่วนขยาย (xml, html ฯลฯ ) ไปยังมุมมอง หากคุณเลือกการแสดงผลเริ่มต้น ( format.html- ไม่มีอาร์กิวเมนต์) มันจะใช้การประชุม (ตาม URL และคำกริยา HTTP) เพื่อเลือกมุมมอง (คาดว่าจะเป็น HTML) ผู้ตอบกลับ (รูปแบบ) ได้รับคำสั่งที่นี่เพื่อแสดง URL ที่ลงท้ายด้วย. json โดยทำให้เป็นอนุกรมกับ json แทนที่จะใช้มุมมองและแบบแผน
Craig Celeste

คำตอบ:


189

ฉันยังใหม่กับ Ruby และติดอยู่ที่รหัสเดียวกันนี้ ส่วนที่ฉันได้วางสายเป็นพื้นฐานเล็กน้อยกว่าคำตอบบางส่วนที่ฉันพบที่นี่ สิ่งนี้อาจช่วยได้หรือไม่ก็ได้

  • respond_toเป็นวิธีการใน ActionControllersuperclass
  • มันใช้เวลาบล็อกซึ่งเป็นเหมือนตัวแทน บล็อกมาจากdoจนกระทั่งendโดย|format|มีอาร์กิวเมนต์เป็นบล็อก
  • response_to ประมวลผลบล็อกของคุณส่งผ่าน Responder ไปยังformatอาร์กิวเมนต์

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

  • Responderไม่ได้มีวิธีการ.htmlหรือ.jsonแต่เราเรียกวิธีการเหล่านี้นะ! ส่วนนี้ทำให้ฉันห่วง
  • 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 ในวิธีเริ่มต้น (ใช้การประชุมและมุมมอง)

มันสามารถเขียนได้เช่นนี้ (ใช้ pseudocode เหมือน 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เราจำเป็นต้องมีตัวอย่างของคลาสดังนั้นเราจึงจำเป็นต้องผ่านการเรียกกลับซึ่งพวกมันผ่านวัตถุคล้ายเมธอด สำหรับคนที่เขียนโค้ดในภาษา C เป็นเวลา 20 ปีนี่เป็นสิ่งที่ล้าหลังและไม่เข้าใจฉัน ไม่ว่ามันจะแย่! แต่มันเป็นสิ่งที่ผู้คนจำนวนมากที่มีพื้นหลังแบบนั้นต้องรีบไปรอบ ๆ และฉันคิดว่าอาจเป็นสิ่งที่ OP ทำ

ป.ล. ทราบว่าใน RoR 4.2 respond_toถูกดึงเข้าไปในอัญมณีผู้ตอบโต้


ขอบคุณ Craig ที่ลิงค์นั้นมีข้อมูลที่เป็นประโยชน์มากมายเช่นกันฉันไม่ได้ตระหนักถึงความเป็นไปได้ที่จะmethod_missingพิจารณาว่าคุณสามารถผ่านการโต้แย้งและบล็อกได้!
Aditya MP

2
คำตอบที่ดีที่สุดสำหรับการอธิบายการใช้ method_missing () เป็นกลไกการลงทะเบียนในคลาส Responder! ฉันสับสนมากกับรหัสนี้
Alan Evangelista

1
เครื่องกำเนิดไฟฟ้านั่งร้าน Rails 6 ดูเหมือนจะสร้างรหัสด้วยrespond_toในตัวควบคุมโดยไม่ต้องมีอัญมณีของผู้ตอบสนองอยู่ใน Gemfile บางทีบิตเกี่ยวกับrespond_toการถูกดึงเข้าไปในอัญมณีของผู้ตอบโต้มีการเปลี่ยนแปลงบ้างไหม?
Qasim

106

นี่คือบล็อกของรหัสทับทิมที่ใช้ประโยชน์จากวิธีการของ Rails helper หากคุณยังไม่คุ้นเคยกับบล็อกคุณจะเห็นพวกเขาเป็นจำนวนมากใน Ruby

respond_toเป็นวิธีการ Rails helper ที่แนบมากับคลาส Controller (หรือมากกว่านั้นเป็นคลาส super) มันคือการอ้างอิงการตอบสนองที่จะถูกส่งไปยังมุมมอง (ซึ่งจะไปที่เบราว์เซอร์)

บล็อกในตัวอย่างของคุณคือการจัดรูปแบบข้อมูล - โดยผ่านพารามิเตอร์ 'รูปแบบ' ในบล็อก - จะถูกส่งจากคอนโทรลเลอร์ไปยังมุมมองเมื่อใดก็ตามที่เบราว์เซอร์ทำการร้องขอข้อมูล html หรือ json

หากคุณอยู่ในเครื่องของคุณและคุณได้ติดตั้งนั่งร้านสำหรับโพสต์คุณสามารถไปที่http://localhost:3000/postsและคุณจะเห็นโพสต์ทั้งหมดของคุณในรูปแบบ html แต่ถ้าคุณพิมพ์สิ่งนี้ http://localhost:3000/posts.jsonคุณจะเห็นโพสต์ทั้งหมดของคุณในวัตถุ json ที่ส่งมาจากเซิร์ฟเวอร์

สิ่งนี้มีประโยชน์มากสำหรับการสร้างจาวาสคริปต์แอปพลิเคชันที่ต้องผ่าน json ไปมาจากเซิร์ฟเวอร์ หากคุณต้องการคุณสามารถสร้าง json api บนรางด้านหลังของคุณได้อย่างง่ายดายและผ่านเพียงมุมมองเดียวเท่านั้นเช่นมุมมองดัชนีของตัวควบคุมโพสต์ จากนั้นคุณสามารถใช้ไลบรารีจาวาสคริปต์เช่นJqueryหรือBackbone (หรือทั้งสองอย่าง) เพื่อจัดการข้อมูลและสร้างส่วนต่อประสานของคุณเอง สิ่งเหล่านี้เรียกว่าUIs แบบอะซิงโครนัสและกำลังได้รับความนิยมอย่างมาก (Gmail คือหนึ่ง) พวกมันเร็วมากและทำให้ผู้ใช้ได้รับประสบการณ์การใช้งานบนเว็บมากขึ้น แน่นอนว่านี่เป็นข้อดีอย่างหนึ่งของการจัดรูปแบบข้อมูลของคุณ

The 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ที่ด้านบนของคลาสคุณสามารถประกาศรูปแบบทั้งหมดที่คุณต้องการให้ตัวควบคุมของคุณส่งไปยังมุมมองของคุณ

จากนั้นในวิธีการควบคุมสิ่งที่คุณต้องทำคือ response_with (@whething_object_you_have)

มันช่วยให้โค้ดของคุณง่ายขึ้นเล็กน้อยกว่าสิ่งที่ Rails สร้างขึ้นโดยอัตโนมัติ

หากคุณต้องการทราบเกี่ยวกับผลงานภายในของ ...

จากสิ่งที่ฉันเข้าใจ Rails จะใคร่ครวญวัตถุเพื่อกำหนดว่ารูปแบบที่แท้จริงนั้นจะเป็นอย่างไร ค่าตัวแปร 'รูปแบบ' ขึ้นอยู่กับวิปัสสนานี้ Rails สามารถทำอะไรได้มากมายด้วยข้อมูลนิดหน่อย คุณจะประหลาดใจกับการ @ @ ง่าย ๆ หรือ: โพสต์จะไป

ตัวอย่างเช่นถ้าฉันมี _user.html.erb ไฟล์บางส่วนที่มีลักษณะเช่นนี้:

_user.html.erb

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

จากนั้นเพียงอย่างเดียวในมุมมองดัชนีของฉันจะทำให้ Rails รู้ว่ามันจำเป็นต้องค้นหา 'ผู้ใช้' บางส่วนและทำซ้ำในวัตถุ 'ผู้ใช้' ทั้งหมด:

index.html.erb

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

จะแจ้งให้ Rails ทราบว่าจำเป็นต้องค้นหา 'ผู้ใช้' บางส่วนและทำซ้ำผ่านวัตถุ 'ผู้ใช้' ทั้งหมด:

คุณอาจพบว่าการโพสต์บล็อกนี้มีประโยชน์: 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
คำแนะนำที่ดีบนทางรถไฟ 3 ฉันยังคงพยายามไปที่ด้านล่างของการตอบกลับเพื่อบล็อกและสิ่งที่อาร์กิวเมนต์ของบล็อก | รูปแบบ | ได้รับผ่าน
โคล

4
คำตอบที่ดี แต่ไม่ได้พูดอะไรเกี่ยวกับตัวแปรรูปแบบที่ถูกส่งผ่านเข้าไปในบล็อก ในตัวอย่างที่ระบุมี format.html และ format.json - ทำทั้งสองอย่างนี้ส่งผ่านไปยัง respons_to และจากนั้น respons_ เพื่อตัดสินใจว่าจะทำอย่างไรกับพวกเขา
แอนโธนี

เมื่อถูกrespond_toและrespond_withแนะนำ ฉันใช้ราง 2.3.5และฉันได้รับNoMethodError (undefined method respond_to)
abbood

10

จากสิ่งที่ฉันรู้ response_to เป็นวิธีการที่แนบมากับ ActionController ดังนั้นคุณสามารถใช้มันได้ในทุก ๆ คอนโทรลเลอร์เพราะมันทั้งหมดสืบทอดมาจาก ActionController นี่คือวิธีการตอบกลับของ Rails:

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**>>

| รูปแบบ | ส่วนหนึ่งเป็นอาร์กิวเมนต์ที่บล็อกคาดหวังดังนั้นภายในเมธอด response_to ที่เราสามารถใช้ได้ อย่างไร?

ถ้าคุณสังเกตเห็นว่าเราผ่านบล็อกด้วยวิธี & prefixed ในวิธี response_to และเราทำเช่นนั้นเพื่อรักษาบล็อกนั้นเป็น Proc เนื่องจากอาร์กิวเมนต์มี ".xml", ".html" เราจึงสามารถใช้วิธีนั้นเป็นวิธีการที่จะเรียกใช้

สิ่งที่เราทำโดยทั่วไปในคลาส response_to คือวิธีการโทร ".html, .xml, .json" ไปยังอินสแตนซ์ของคลาส Responder


1
แหล่งที่มาสำหรับ respons_to ใน api docs ต่างจากแหล่งที่คุณรวมไว้และกำลังไล่ฉันออกไป ตัวอย่างของคุณทำให้ฉันชัดเจนว่าอาร์กิวเมนต์รูปแบบบล็อกกำลังถูกส่งผ่านวัตถุ Responder เอกสารตอบกลับดูเหมือนจะตอบคำถามโดยอ่านตอนนี้
โคล

7

ฉันต้องการที่จะเข้าใจว่าการตอบสนองการปิดกั้นการทำงานจริง รูปแบบของตัวแปรชนิดใด .html และ. json เป็นวิธีการจัดรูปแบบวัตถุหรือไม่

เพื่อที่จะเข้าใจในสิ่งที่formatเป็นครั้งแรกที่คุณสามารถดูแหล่งสำหรับrespond_toแต่อย่างรวดเร็วคุณจะพบว่าจริงๆสิ่งที่คุณต้องดูที่เป็นรหัสสำหรับretrieve_response_from_mimes

จากที่นี่คุณจะเห็นว่าบล็อกที่ถูกส่งผ่านไปยังrespond_to(ในรหัสของคุณ) ได้รับการเรียกและส่งผ่านด้วยอินสแตนซ์ของนักสะสม (ซึ่งภายในบล็อกถูกอ้างอิงเป็นformat) นักสะสมสร้างวิธีการโดยทั่วไป (ฉันเชื่อว่าการเริ่มต้นทำงานกับ Rails) ขึ้นอยู่กับสิ่งที่ประเภทของรางรถไฟที่รู้

ดังนั้นใช่.htmlและ.jsonมีการกำหนดวิธีการ (ที่รันไทม์) ในformatคลาสCollector (aka )


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

บรรทัด csv จะทำให้ to_csv ถูกเรียกในแต่ละโพสต์เมื่อคุณไปที่ /posts.csv ทำให้ง่ายต่อการส่งออกข้อมูลเป็น CSV (หรือรูปแบบอื่น ๆ ) จากเว็บไซต์ Rails ของคุณ

บรรทัด js จะทำให้ไฟล์ javascript /posts.js (หรือ / posts.js.coffee) ไฟล์ถูกเรนเดอร์ / ดำเนินการ ฉันพบว่าเป็นวิธีที่มีน้ำหนักเบาในการสร้างไซต์ที่เปิดใช้งาน Ajax โดยใช้ป๊อปอัป jQuery UI


1

รูปแบบของตัวแปรชนิดใด

จากจาวา POV, การจัดรูปแบบเป็นการใช้อินเทอร์เฟซที่ไม่ระบุชื่อ อินเตอร์เฟสนี้มีวิธีการหนึ่งชื่อสำหรับแต่ละประเภท mime เมื่อคุณเรียกใช้หนึ่งในวิธีการเหล่านั้น (ผ่านบล็อก) ถ้ารางรู้สึกว่าผู้ใช้ต้องการประเภทเนื้อหานั้นมันจะเรียกบล็อกของคุณ

แน่นอนว่าสิ่งที่บิดเบี้ยวคือวัตถุกาวที่ไม่ระบุชื่อนี้ไม่ได้ใช้อินเทอร์เฟซจริงๆมันจับวิธีการโทรแบบไดนามิกและทำงานได้ถ้าชื่อของประเภท mime ที่รู้

ส่วนตัวผมคิดว่ามันดูแปลก: บล็อกที่คุณผ่านในจะดำเนินการ มันจะทำให้ฉันผ่านไปได้มากขึ้นในการแฮชป้ายและบล็อกรูปแบบ แต่ - นั่นเป็นวิธีที่ทำได้ใน RoR ดูเหมือนว่า


1

นี่เป็นเรื่องที่ล้าสมัยเล็กน้อยโดย Ryan Bigg ทำงานได้ดีมากในการอธิบายเรื่องนี้ที่นี่:

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

ในความเป็นจริงมันอาจเป็นรายละเอียดเล็กน้อยกว่าที่คุณต้องการ เมื่อปรากฎว่ามีฉากเกิดขึ้นมากมายรวมถึงความต้องการที่จะเข้าใจว่า MIME ประเภทโหลดได้อย่างไร


0

"Format" เป็นประเภทการตอบกลับของคุณ อาจเป็น json หรือ html เป็นรูปแบบของผลลัพธ์ที่ผู้เข้าชมจะได้รับ


0

มีอีกสิ่งหนึ่งที่คุณควรระวัง - MIME

หากคุณต้องการใช้ประเภท MIME และไม่ได้รับการสนับสนุนตามค่าเริ่มต้นคุณสามารถลงทะเบียนเครื่องมือจัดการของคุณใน config / initializers / mime_types.rb:

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.