जब आप रेल्स में एक स्कैफोल्ड उत्पन्न करते हैं, तो आप सामान्य 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 त्रुटि होती, तो आप एक बेहतर रिस्पांस कोड वापस कर सकते थे। इसके बजाय, ये त्रुटियां अन्य, असंबंधित त्रुटियों के साथ मिल जाएंगी, और उन्हें संभालना वास्तव में कठिन होगा।
आप अपने index एक्शन में एक respond_to ब्लॉक जोड़ सकते हैं:
# 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 से भर देना पागलपन है। यह अन-रेल्स जैसा लगता है। यह DRY का उल्लंघन करता है। और यह आपको उस काम से विचलित करता है जो आपका कंट्रोलर वास्तव में कर रहा है।
आप अभी भी खराब फॉर्मेट को सही ढंग से संभालना चाहते हैं। तो आप क्या करते हैं?
एक respond_to शॉर्टकट
यदि आप अपने ऑब्जेक्ट्स को रेंडर करने के लिए कुछ खास नहीं कर रहे हैं, तो आप एक शॉर्टकट ले सकते हैं। यदि आप लिखते हैं:
def index
@tasks = Task.all
respond_to :html, :json
end
यह index में पूर्ण respond_to ब्लॉक लिखने के समान ही काम करता है। यह आपके एक्शन द्वारा समर्थित सभी फॉर्मेट्स के बारे में रेल्स को बताने का एक छोटा तरीका है। और यदि अलग-अलग एक्शन अलग-अलग फॉर्मेट्स का समर्थन करते हैं, तो यह उन अंतरों को बिना अधिक कोड के संभालने का एक अच्छा तरीका है।
कंट्रोलर लेवल पर फॉर्मेट्स को संभालें
आमतौर पर, हालांकि, आपके कंट्रोलर में प्रत्येक एक्शन उसी फॉर्मेट्स के साथ काम करेगा। यदि 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
इस तरह, आप अपने कोड को उन फॉर्मेट्स से अलग करते हैं जिनका आप जवाब देते हैं। आप रेल्स को एक बार बता सकते हैं कि आप कौन से फॉर्मेट्स संभालना चाहते हैं। आपको उन्हें हर एक्शन में दोहराने की ज़रूरत नहीं है।
द रेस्पॉन्डर्स जेम
रेल्स 4.2 में, एक पकड़ है: respond_with अब शामिल नहीं है। लेकिन आप इसे वापस पा सकते हैं यदि आप responders जेम इंस्टॉल करते हैं। और responders जेम इसके साथ कुछ अन्य अच्छी फीचर्स लाता है।
आप अपने कंट्रोलर के शीर्ष पर responders :flash शामिल करके respond_with में फ्लैश मैसेज सेट कर सकते हैं:
class TasksController < ApplicationController
responders :flash
सुविधाजनक रूप से, आप इन फ्लैश मैसेज के लिए डिफ़ॉल्ट सेट कर सकते हैं अपने लोकेल फाइलों में।
इसके अलावा, यदि आपके Gemfile में responders जेम है और आप एक रेल्स स्कैफोल्ड उत्पन्न करते हैं, तो जनरेटर respond_to के बजाय respond_with का उपयोग करके कंट्रोलर्स बनाएगा:
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
# ...
यह रेल्स के साथ आने वाले स्कैफोल्ड्स की तुलना में बहुत क्लीनर है।
और अंत में, यदि आप केवल विशिष्ट कंट्रोलर एक्शन के लिए एक फॉर्मेट के साथ जवाब देना चाहते हैं, तो आप respond_to को कई बार कॉल कर सकते हैं:
class TasksController < ApplicationController
respond_to :html
respond_to :js, only: :create
end
उस अंतिम टिप के लिए टिप्पणियों में जेरोन वेइंक को धन्यवाद!
respond_with या respond_to?
यदि आप अलग-अलग फॉर्मेट्स के लिए अलग-अलग जानकारी वापस करना चाहते हैं, तो आपके पास कुछ विकल्प हैं। कंट्रोलर-लेवल respond_to respond_with के साथ संयुक्त छोटे कंट्रोलर्स प्राप्त करने का एक शानदार तरीका है। लेकिन यह सबसे अधिक मदद करता है जब आपके सभी कंट्रोलर एक्शन उसी फॉर्मेट का जवाब देते हैं, और उस तरह से कार्य करते हैं जिस तरह रेल्स उनसे उम्मीद करता है।
कभी-कभी, हालांकि, आप कुछ एक्शन चाहते हैं जो अलग तरह से कार्य करें। वन-लाइनर respond_to उस स्थिति को संभालने के लिए बहुत अच्छा है।
यदि आपको अधिक नियंत्रण की आवश्यकता है, तो ब्लॉक के साथ पूर्ण respond_to का उपयोग करें, और आप प्रत्येक फॉर्मेट को जैसे चाहें वैसे संभाल सकते हैं।
इनमें से किसी के साथ, आपके द्वारा समर्थित नहीं फॉर्मेट्स के लिए अनुरोधों को सही त्रुटि मिलेगी। और आपका ऐप और इसके क्लाइंट बहुत कम भ्रमित होंगे।