রেলসের সাথে কাজ করার একটি সুন্দর দিক হলো যখন ডেভেলপমেন্ট মোডে কিছু এক্সেপশন ঘটে, তবে আপনি একটি খুব সুন্দর এরর ডিটেইল পেজ পান। আপনি একটি সুন্দর ব্যাকট্রেস পান, আপনার অ্যাপের সাথে রিলেভেন্ট অংশগুলো হাইলাইট করা থাকে। আপনি পোস্ট করা প্যারামস দেখতে পান, 뿐만큼 এনভায়রনমেন্ট এবং সেশন ভেরিয়েবলও ইন্সপেক্ট করতে পারেন।
আজ আমরা দেখব এই ফ্যান্সি এরর পেজগুলো কীভাবে কাজ করে।

Actionpack খোলা
আজ আমরা যে ফাইলটির সাথে সবচেয়ে বেশি কাজ করব সেটি হলো actionpack/lib/action_dispatch/middleware/debug_exceptions.rb। ডেভেলপমেন্ট মোডের এরর পেজ ডিসপ্লে করার ক্ষেত্রে এটিই মূলভাবে সব ভারি লিফ্টিং করে। আপনি যদি প্রোডাকশন মোডের এরর স্ক্রিনের উৎস জানতে চান, তবে public_exceptions.rb চেক করুন।
Rack Middleware
আপনি যদি rack middleware-র সাথে পরিচিত নন, কনসেপ্টটি সিম্পল। এটি আপনাকে HTTP রিকোয়েস্ট ইন্টারসেপ্ট করতে দেয় আপনার অ্যাপে পৌঁছানোর আগে, এবং অ্যাপের আউটপুট ইন্টারসেপ্ট করতে দেয় ইউজারের কাছে ফিরে যাওয়ার আগে।
এখানে একটি সিম্পল মিডলওয়্যার যা কিছুই ইন্টেরেস্টিং করে না।
class MyMiddleware def initialize(app) @app = app end def call(env) @app.call(env) end end Rack middleware দিয়ে সকল এক্সেপশন রেসকিউ করা
আপনার অ্যাপে যেকোনো এক্সেপশন ঘটে @app.call() কল করার ফলাফলস্বরূপ। তাই একটি rack অ্যাপে সকল এক্সেপশন রেসকিউ করা খুব সহজ: মিডলওয়্যারের রেসকিউ ক্লেজ যোগ করুন।
def call(env) @app.call(env) rescue StandardError => exception # এই মেথডটি আমাদের দরকার যা এক্সেপশন পেজ জেনারেট করবে render_exception(env, exception) end call মেথড থেকে যেকোনো কিছু রিটার্ন হলে, সেটিকে একটি নরমাল ওয়েব পেজের মত ট्रीট করা হয়। তাই render_exception দিয়ে রিটার্ন হওয়া কনটেন্ট ওরিজিনাল রেসপন্সকে রিপ্লেস করে।
এক্সেপশন রেন্ডার করা
আমি ActionDispatch::DebugExceptions-র render_exception মেথডটি এক্সসার্প্ট করলাম। আপনি দেখতে পাচ্ছেন, এটি সিম্পলি এক্সেপশন থেকে রিলেভেন্ট ডেটা পুল করে এবং একটি ERB টেমপ্লেটে ফিড করে।
def render_exception(env, exception) wrapper = ExceptionWrapper.new(env, exception) log_error(env, wrapper) if env['action_dispatch.show_detailed_exceptions'] request = Request.new(env) template = ActionView::Base.new([RESCUES_TEMPLATE_PATH], request: request, exception: wrapper.exception, application_trace: wrapper.application_trace, framework_trace: wrapper.framework_trace, full_trace: wrapper.full_trace, routes_inspector: routes_inspector(exception), source_extract: wrapper.source_extract, line_number: wrapper.line_number, file: wrapper.file ) file = "rescues/#{wrapper.rescue_template}" if request.xhr? body = template.render(template: file, layout: false, formats: [:text]) format = "text/plain" else body = template.render(template: file, layout: 'rescues/layout') format = "text/html" end render(wrapper.status_code, body, format) else raise exception end end def render(status, body, format) [status, {'Content-Type' => "#{format}; charset=#{Response.default_charset}", 'Content-Length' => body.bytesize.to_s}, [body]] end অন্যান্য ব্যবহার
আপনি এই rack middleware ট্রিক ব্যবহার করে এক্সেপশনসহ অনেক ইন্টেরেস্টিং জিনিস করতে পারেন। Honeybadger-এ আমরা এটি ব্যবহার করি এরর ইন্টারসেপ্ট করে আমাদের API-তে রেকর্ড করার জন্য। আমরা যে কোডটি ব্যবহার করি সেটি নিচে:
def call(env) config.with_request(::Rack::Request.new(env)) do begin env['honeybadger.config'] = config response = @app.call(env) rescue Exception => raised env['honeybadger.error_id'] = notify_honeybadger(raised, env) raise end framework_exception = framework_exception(env) if framework_exception env['honeybadger.error_id'] = notify_honeybadger(framework_exception, env) end response end ensure Honeybadger.context.clear! end