มาต่อกัน ยังไม่จบ
คราวนี้เข้ามาข้างใน controller กันบ้าง ฝั่ง logic ข้ามไป มาดูตรง respond_to กันดีกว่า
1 2 3 4 5 6 | respond_to do |format| format.html # index.rhtml format.js # index.rjs ผมเพิ่มเอง format.xml { render :xml => @products.to_xml } format.rss { render :action => "rss.rxml" } # อันนี้ผมก็เพิ่มเอง end |
คงจะเห็น code อันนี้ใน index หรือใน create จะเห็น
1 2 3 4 5 6 7 8 9 10 | respond_to do |format| if @product.save flash[:notice] = 'Product was successfully created.' format.html { redirect_to product_url(@product) } format.xml { head :created, :location => product_url(@product) } else format.html { render :action => "new" } format.xml { render :xml => @product.errors.to_xml } end end |
มันไว้ทำอะไร ??? มันจัดการกับ mime type นั่นแล ซึ่งขึ้นอยู่กับ request ที่ส่งมา ว่าต้องการ respond เป็นอะไรกลับไป ถ้าต้องการ html ก็ใช้วิธีปกติที่เคยทำกัน แต่ถ้าเกิดต้องการในรูปของ xml ก็เพียง request มาว่าต้องการ xml ซึ่ง Rails จะไปจัดการกับ HTTP Accept header จากที่ request มาเอง
ทำไมต้อง xml ?? ก็เพราะว่า Web Services หนะสิ แค่ request มา แล้วมันก็จะ return เป็น xml ไปให้ แค่นี้ไม่ว่าภาษาใดๆ ก็จะเข้าใจได้้้ด้วย xml แล้ว
มาดูในตัวอย่าง ถ้าเกิดส่ง url มาเป็น /products แน่นอน มันย่อม render ออกไปเป็น index.rhtml แต่ถ้าเป็น /products.xml มันก็จะ render เป็น xml ให้ โดยใช้ attribute เป็นตัวกำหนด node (อันนี้ลองเล่นกันเองนะครับ)
ถ้าเป็น ajax เรียกมา มันก็จะไป render ตัว index.rjs(อันนี้ก็สนุก สำหรับ ajax แปะไว้ๆ) หรือถ้าเป็น /products.rss มันก็จะไป render ตัว index.rxml ซึ่งทั้ง .js และ .rxml ก็มีรูปแบบของมันอยู่ ไว้จะย้อนมาเล่าให้ฟังทีหลัง สำหรับ rss หรือ atom จริงๆ แล้วมี plugin ช่วย ใช้ plugin จะผ่อนแรงกว่าเยอะ
ส่วนอันที่เป็น create ถ้าใช้ HTML ก็ปกติดี แต่ถ้าเกิดต้องการเป็น Web Services ให้สร้าง header ให้มีหน้าตาแบบนี้(ประยุกต์และอ้างอิงจาก DHH)
1 2 3 4 5 6 7 8 9 10 11 | POST /products/create HTTP/1.1 Host: example.org User-Agent: Thingio/1.0 Accept: application/xml Content-Type: application/xml Content-Length: nnn <product> <name>First product!!</name> <description>This is a book</description> </product> |
เนื่องจาก Content-Type เป็น application/xml ตัว rails เลยทำการแปลงให้อยู่ในรูปของ "product[name]=First%20product!!&product[description]=This%20is%20a%20book" ซึ่งเป็น form ปกติที่ใช้อยู่ ซึ่งตัว Content-Type จะเป็นตัวบอกว่าให้ xml มานะ ส่วนตัว Accept จะเป็นตัวบอกว่า ของที่คุณต้องเรียกใช้ ก็เป็น xml เหมือนกันนะ เพื่อให้มันรับรูปอย่างชัดเจนในการ respond แล้วมันก็จะวิ่งไปที่ format.xml เอง ถ้าจะใช้ WS กับ rails ชุดนี้ อย่าลืมระบุ Accept มาด้วยนะครับ
หลังจากที่ทำการสร้างให้เสร็จแล้ว มันก็จะส่ง header กลับไป หน้าตาที่มันถูกสร้าง จะเป็นแบบนี้
HTTP/1.1 201 Created
Content-Length: 0
Location: http://example.org/products/show/1
|
ในกรณีที่เราต้องการที่จะระบุ mime type เพิ่มเติม สามารถไปเพิ่มได้ที่ config/environment.rb
Mime::Type.register "image/jpg", :jpg
เพิ่งนึงถึง DRY ได้ ว่ามันเข้า concept ของ DRY พอดี เราไม่ต้องทำซ้ำ ไม่ว่าจะต้องการ respond แบบไหนเราก็ทำเพียงครั้งเดียว ง่ายต่อการ maintenance
นี่แล ความเมามันส์ของ RESTful
ปล. rails มันส์กว่า ruby เพียวๆ แฮะ แก้ไขครั้งที่ 1 : เพิ่งนึกได้ว่า ถ้าหากเป็น method ที่ไม่ได้เกี่ยวกับ CRUD ถ้าจะ render ตามที่สั่งใน format ไว้ ให้เพิ่ม ?format=your_format ไปด้วย เช่น ?format=xml
แก้ไขล่าสุด วันที่ 28 กรกฏาคม 2550 เวลา 1.34 น.