เมื่อคุณสร้างนั่งร้านใน Rails คุณจะเห็น respond_to
ปกติ บล็อก:
def destroy
@task.destroy
respond_to do |format|
format.html { redirect_to tasks_url, notice: 'Task was successfully destroyed.' }
format.json { head :no_content }
end
end
แต่การกระทำบางอย่างของคุณ เช่น index
ไม่ได้มีพวกเขา!
# GET /tasks
# GET /tasks.json
def index
@tasks = Task.all
end
นี้ไม่ดี. ทำไม หากคุณกด /tasks.txt
และ txt
แอปของคุณไม่รองรับ คุณจะได้รับข้อผิดพลาดที่ไม่ถูกต้อง:
ActionView::MissingTemplate (Missing template tasks/index, application/index with {:locale=>[:en], :formats=>[:text], :variants=>[], :handlers=>[:erb, :builder, :raw, :ruby, :coffee, :jbuilder]}
นี่ไม่ถูกต้องนัก คุณควรบอกลูกค้าว่าพวกเขากำลังขอรูปแบบที่คุณไม่สนับสนุน ไม่ใช่ว่าคุณไม่พบไฟล์ที่ถูกต้อง
หากเป็น UnknownFormat
ผิดพลาด คุณสามารถส่งคืนรหัสตอบกลับที่ดีกว่าได้ แต่ข้อผิดพลาดเหล่านี้จะปะปนกับข้อผิดพลาดอื่นๆ ที่ไม่เกี่ยวข้อง และจะจัดการได้ยากจริงๆ
คุณสามารถเพิ่ม respond_to
บล็อก index
. ของคุณ การกระทำ:
# GET /tasks
# GET /tasks.json
def index
@tasks = Task.all
respond_to do |format|
format.html
format.json
end
end
จากนั้น คุณจะได้รับข้อยกเว้นและรหัสข้อผิดพลาดที่คุณคาดหวัง:
Started GET "/tasks.txt" for 127.0.0.1 at 2014-11-03 22:05:12 -0800
Processing by TasksController#index as TEXT
Completed 406 Not Acceptable in 21ms
ActionController::UnknownFormat (ActionController::UnknownFormat):
app/controllers/tasks_controller.rb:8:in `index'
ดีขึ้นมาก แต่ทิ้งผู้ควบคุมทั้งหมดของคุณด้วย respond_to
บ้าไปแล้ว มันให้ความรู้สึก un-Rails-ish มันละเมิด DRY และทำให้คุณเสียสมาธิจากงานที่ตัวควบคุมของคุณกำลังทำอยู่
คุณยังต้องการจัดการรูปแบบที่ไม่ดีอย่างถูกต้อง แล้วคุณจะทำอย่างไร?
A respond_to
ทางลัด
หากคุณไม่ได้ทำอะไรเป็นพิเศษเพื่อแสดงวัตถุ คุณสามารถใช้ทางลัดได้ หากคุณเขียน:
def index
@tasks = Task.all
respond_to :html, :json
end
มันทำงานในลักษณะเดียวกับการเขียน respond_to
. แบบเต็ม บล็อกใน index
. เป็นวิธีสั้นๆ ในการบอก Rails เกี่ยวกับรูปแบบทั้งหมดที่การกระทำของคุณรู้ และหากการกระทำต่างกันรองรับรูปแบบที่ต่างกัน นี่เป็นวิธีที่ดีในการจัดการความแตกต่างเหล่านั้นโดยไม่ต้องใช้โค้ดมากนัก
จัดการรูปแบบที่ระดับคอนโทรลเลอร์
โดยปกติแล้ว แต่ละการกระทำในคอนโทรลเลอร์ของคุณจะทำงานกับ เหมือนกัน รูปแบบ ถ้า index
ตอบกลับ json
ดังนั้นจะ new
และ create
และทุกสิ่งทุกอย่าง ดังนั้น คงจะดีถ้าคุณมี respond_to
ที่จะส่งผลต่อตัวควบคุมทั้งหมด:
class TasksController < ApplicationController
before_action :set_task, only: [:show, :edit, :update, :destroy]
respond_to :html, :json
# GET /tasks
# GET /tasks.json
def index
@tasks = Task.all
respond_with(@tasks)
end
และสิ่งนี้ได้ผลจริง:
Started GET "/tasks.txt" for 127.0.0.1 at 2014-11-03 22:17:37 -0800
Processing by TasksController#index as TEXT
Completed 406 Not Acceptable in 7ms
ActionController::UnknownFormat (ActionController::UnknownFormat):
app/controllers/tasks_controller.rb:8:in `index'
ชนิดของข้อผิดพลาดที่เราหวังว่าจะได้รับ! และคุณไม่ต้องวุ่นวายกับแต่ละการกระทำเพื่อทำสิ่งนั้น
บางครั้ง คุณต้องการทำสิ่งต่าง ๆ ขึ้นอยู่กับสถานะของโมเดล ตัวอย่างเช่น สำหรับ create
คุณจะเปลี่ยนเส้นทางหรือแสดงแบบฟอร์มอีกครั้ง ขึ้นอยู่กับว่าโมเดลนั้นถูกต้องหรือไม่
รางสามารถจัดการสิ่งนี้ได้ แต่คุณยังคงต้องบอกว่าต้องการให้ตรวจสอบวัตถุใดด้วย respond_with
. ดังนั้นแทนที่จะเป็น:
def create
@task = Task.new(task_params)
respond_to do |format|
if @task.save
format.html { redirect_to @task, notice: 'Task was successfully created.' }
format.json { render :show, status: :created, location: @task }
else
format.html { render :new }
format.json { render json: @task.errors, status: :unprocessable_entity }
end
end
end
คุณสามารถเขียน:
def create
@task = Task.new(task_params)
flash[:notice] = "Task was successfully created." if @task.save
respond_with(@task)
end
ด้วยวิธีนี้ คุณจะแยกโค้ดของคุณออกจากรูปแบบที่คุณตอบกลับ คุณสามารถบอก Rails ได้ ครั้งเดียว รูปแบบใดที่คุณต้องการจัดการ คุณไม่จำเป็นต้องทำซ้ำในทุกการกระทำ
อัญมณีตอบกลับ
ใน Rails 4.2 มีสิ่งที่จับต้องได้:respond_with
ไม่รวมอีกต่อไป แต่คุณสามารถกู้คืนได้หากคุณติดตั้ง responders
พลอย และ responders
gem นำคุณสมบัติที่ดีอื่น ๆ มาด้วย
คุณสามารถตั้งค่าข้อความแฟลชใน respond_with
โดยใส่ responders :flash
ที่ด้านบนของคอนโทรลเลอร์ของคุณ:
class TasksController < ApplicationController
responders :flash
สะดวกสบาย คุณสามารถตั้งค่าเริ่มต้นสำหรับข้อความแฟลชเหล่านี้ในไฟล์ภาษาของคุณ
นอกจากนี้ หากคุณมี responders
อัญมณีใน Gemfile
. ของคุณ และคุณสร้างโครงนั่งร้าน Rails ตัวสร้างจะสร้างตัวควบคุมโดยใช้ respond_with
แทน respond_to
:
class TasksController < ApplicationController
before_action :set_task, only: [:show, :edit, :update, :destroy]
respond_to :html, :json
def index
@tasks = Task.all
respond_with(@tasks)
end
def show
respond_with(@task)
end
# ...
นี้สะอาดกว่านั่งร้าน Rails มาก
และสุดท้าย หากคุณต้องการตอบสนองด้วยรูปแบบเฉพาะสำหรับการดำเนินการกับตัวควบคุม คุณสามารถเรียก respond_to
หลายครั้ง:
class TasksController < ApplicationController
respond_to :html
respond_to :js, only: :create
end
ขอบคุณ Jeroen Weeink ในความคิดเห็นสำหรับเคล็ดลับสุดท้ายนั้น!
respond_with
หรือ respond_to
?
หากคุณต้องการส่งคืนข้อมูลที่แตกต่างกันสำหรับรูปแบบต่างๆ คุณมีทางเลือกสองสามทาง respond_to
ระดับคอนโทรลเลอร์ รวมกับ respond_with
เป็นวิธีที่ยอดเยี่ยมในการรับตัวควบคุมแบบสั้น แต่มีแนวโน้มว่าจะช่วยได้มากที่สุดเมื่อการกระทำของผู้ควบคุมทั้งหมดตอบสนองต่อรูปแบบเดียวกัน และดำเนินการในลักษณะที่ Rails คาดหวัง
แม้ว่าในบางครั้ง คุณต้องการให้มีการกระทำบางอย่างที่แตกต่างออกไป เส้นเดียว respond_to
เหมาะสำหรับรับมือสถานการณ์นั้น
หากคุณต้องการการควบคุมเพิ่มเติม ให้ใช้ respond_to
. แบบเต็ม ด้วยบล็อก และคุณสามารถจัดการแต่ละรูปแบบได้ตามที่คุณต้องการ
ในกรณีเหล่านี้ คำขอรูปแบบที่คุณไม่สนับสนุนจะได้รับข้อผิดพลาดที่ถูกต้อง และทั้งแอปและไคลเอ็นต์ของแอปจะยิ่งสับสนน้อยลงมาก