जवाबों:
अपने आप को 404 रेंडर न करें, इसका कोई कारण नहीं है; रेल में यह कार्यक्षमता पहले से ही निर्मित है। यदि आप 404 पृष्ठ दिखाना चाहते हैं , तो इस तरह से एक render_404
विधि (या not_found
जैसा कि मैंने इसे बुलाया था) बनाएँ ApplicationController
:
def not_found
raise ActionController::RoutingError.new('Not Found')
end
रेल भी संभालती है AbstractController::ActionNotFound
, और ActiveRecord::RecordNotFound
उसी तरह।
इससे दो चीजें बेहतर होती हैं:
1) यह 'में निर्मित रेल का उपयोग करता है rescue_from
404 पेज को रेंडर करने के लिए हैंडलर , और 2) यह आपके कोड के निष्पादन में बाधा डालता है, जिससे आप अच्छे काम कर सकते हैं:
user = User.find_by_email(params[:email]) or not_found
user.do_something!
बदसूरत सशर्त बयान लिखने के लिए बिना।
एक बोनस के रूप में, यह परीक्षणों में संभालना भी आसान है। उदाहरण के लिए, rspec एकीकरण परीक्षण में:
# RSpec 1
lambda {
visit '/something/you/want/to/404'
}.should raise_error(ActionController::RoutingError)
# RSpec 2+
expect {
get '/something/you/want/to/404'
}.to raise_error(ActionController::RoutingError)
और न्यूनतम:
assert_raises(ActionController::RoutingError) do
get '/something/you/want/to/404'
end
या Rails से अधिक जानकारी का संदर्भ दें 404 एक नियंत्रक कार्रवाई से नहीं मिला
ActionController::RecordNotFound
है कि बेहतर विकल्प है?
expect { visit '/something/you/want/to/404' }.to raise_error(ActionController::RoutingError)
/ stackoverflow.com/a/1722839/993890 के
एक 404 हेडर वापस करने के लिए, बस :status
रेंडर विधि के लिए विकल्प का उपयोग करें ।
def action
# here the code
render :status => 404
end
यदि आप मानक 404 पृष्ठ को रेंडर करना चाहते हैं तो आप एक विधि में सुविधा को निकाल सकते हैं।
def render_404
respond_to do |format|
format.html { render :file => "#{Rails.root}/public/404", :layout => false, :status => :not_found }
format.xml { head :not_found }
format.any { head :not_found }
end
end
और इसे अपनी कार्रवाई में कॉल करें
def action
# here the code
render_404
end
यदि आप चाहते हैं कि कार्रवाई त्रुटि पृष्ठ को प्रस्तुत करने और बंद करने के लिए हो, तो बस वापसी विवरण का उपयोग करें।
def action
render_404 and return if params[:something].blank?
# here the code that will never be executed
end
यह भी याद रखें कि रेल कुछ ActiveRecord त्रुटियों को बचाती है, जैसे कि ActiveRecord::RecordNotFound
कि 404 त्रुटि पृष्ठ प्रदर्शित करना।
इसका मतलब है कि आपको इस क्रिया को स्वयं करने की आवश्यकता नहीं है
def show
user = User.find(params[:id])
end
User.find
ActiveRecord::RecordNotFound
जब उपयोगकर्ता मौजूद नहीं है तो उठाता है। यह एक बहुत शक्तिशाली विशेषता है। निम्नलिखित कोड को देखें
def show
user = User.find_by_email(params[:email]) or raise("not found")
# ...
end
आप चेक को रेल को सौंपकर इसे सरल बना सकते हैं। बस धमाकेदार संस्करण का उपयोग करें।
def show
user = User.find_by_email!(params[:email])
# ...
end
स्टीवन सोरोका द्वारा प्रस्तुत नया चयनित जवाब करीब है, लेकिन पूरा नहीं है। परीक्षण खुद इस तथ्य को छुपाता है कि यह एक सच्चा 404 नहीं लौटा रहा है - यह 200 की स्थिति लौटा रहा है - "सफलता"। मूल उत्तर करीब था, लेकिन लेआउट को प्रस्तुत करने का प्रयास किया जैसे कि कोई विफलता नहीं हुई थी। यह सब कुछ ठीक करता है:
render :text => 'Not Found', :status => '404'
यहाँ मेरा एक विशिष्ट परीक्षण सेट है, जिसके लिए मुझे आरएसपीईसी और शोता माचिस का उपयोग करके 404 लौटाने की उम्मीद है:
describe "user view" do
before do
get :show, :id => 'nonsense'
end
it { should_not assign_to :user }
it { should respond_with :not_found }
it { should respond_with_content_type :html }
it { should_not render_template :show }
it { should_not render_with_layout }
it { should_not set_the_flash }
end
इस स्वस्थ व्यामोह ने मुझे सामग्री-प्रकार के बेमेल को देखने की अनुमति दी जब बाकी सब कुछ पेचीदा लग रहा था :) मैं इन सभी तत्वों की जांच करता हूं: असाइन किए गए चर, प्रतिक्रिया कोड, प्रतिक्रिया सामग्री प्रकार, टेम्पलेट प्रदान, लेआउट प्रदान, फ्लैश संदेश।
मैं कड़ाई से html ... कभी-कभी अनुप्रयोगों पर सामग्री प्रकार की जाँच छोड़ दूँगा। सब के बाद, "एक संदेहवादी सभी दराज की जांच करता है" :)
http://dilbert.com/strips/comic/1998-01-20/
FYI करें: मैं उन चीजों के लिए परीक्षण की अनुशंसा नहीं करता, जो नियंत्रक में हो रही हैं, अर्थात "should_raise"। आप जिस चीज की परवाह करते हैं वह आउटपुट है। ऊपर दिए गए मेरे परीक्षणों ने मुझे विभिन्न समाधानों की कोशिश करने की अनुमति दी, और परीक्षण एक ही रहते हैं कि क्या समाधान एक अपवाद, विशेष प्रतिपादन आदि उठा रहा है।
render :text => 'Not Found', :status => :not_found
:।
config.consider_all_requests_local
आपकी environments/development.rb
फ़ाइल में सही करने के लिए सेट पैरामीटर है । यदि आप कोई त्रुटि उठाते हैं, जैसा कि स्वीकृत समाधान में वर्णित है, मंचन / उत्पादन में, आपको निश्चित रूप से एक 404 मिलेगा, 200 नहीं।
आप रेंडर फ़ाइल का उपयोग भी कर सकते हैं:
render file: "#{Rails.root}/public/404.html", layout: false, status: 404
आप लेआउट का उपयोग करना चुन सकते हैं या नहीं।
एक अन्य विकल्प इसे नियंत्रित करने के लिए अपवाद का उपयोग करना है:
raise ActiveRecord::RecordNotFound, "Record not found."
चयनित उत्तर रेल 3.1+ में काम नहीं करता है क्योंकि त्रुटि हैंडलर को एक मिडलवेयर में ले जाया गया था ( जीथब मुद्दा देखें) )।
यहाँ समाधान है जो मैंने पाया है कि मैं बहुत खुश हूँ।
इन ApplicationController
:
unless Rails.application.config.consider_all_requests_local
rescue_from Exception, with: :handle_exception
end
def not_found
raise ActionController::RoutingError.new('Not Found')
end
def handle_exception(exception=nil)
if exception
logger = Logger.new(STDOUT)
logger.debug "Exception Message: #{exception.message} \n"
logger.debug "Exception Class: #{exception.class} \n"
logger.debug "Exception Backtrace: \n"
logger.debug exception.backtrace.join("\n")
if [ActionController::RoutingError, ActionController::UnknownController, ActionController::UnknownAction].include?(exception.class)
return render_404
else
return render_500
end
end
end
def render_404
respond_to do |format|
format.html { render template: 'errors/not_found', layout: 'layouts/application', status: 404 }
format.all { render nothing: true, status: 404 }
end
end
def render_500
respond_to do |format|
format.html { render template: 'errors/internal_server_error', layout: 'layouts/application', status: 500 }
format.all { render nothing: true, status: 500}
end
end
और इसमें application.rb
:
config.after_initialize do |app|
app.routes.append{ match '*a', :to => 'application#not_found' } unless config.consider_all_requests_local
end
और मेरे संसाधनों में (शो, एडिट, अपडेट, डिलीट):
@resource = Resource.find(params[:id]) or not_found
यह निश्चित रूप से सुधार किया जा सकता है, लेकिन कम से कम, मेरे पास कोर रेल कार्यों को ओवरराइड किए बिना not_found और internal_error के लिए अलग-अलग विचार हैं।
|| not_found
भाग की आवश्यकता नहीं है , बस कॉल करें find!
(धमाके की सूचना दें) और यह ActiveRecord को फेंक देगा :: RecordNotFound जब संसाधन पुनर्प्राप्त नहीं किया जा सकता है। इसके अलावा, ActiveRecord :: अगर स्थिति में सरणी में RecordNotFound जोड़ें।
StandardError
और नहीं Exception
, सिर्फ मामले में होगा। वास्तव में मैं मानक 500 स्थैतिक पृष्ठ छोड़ दूंगा और कस्टम का उपयोग नहीं render_500
करूंगा, जिसका अर्थ है कि मैं स्पष्ट रूप rescue_from
से 404 से संबंधित त्रुटियों का सरणी
ये आपकी मदद करेंगे ...
आवेदन नियंत्रक
class ApplicationController < ActionController::Base
protect_from_forgery
unless Rails.application.config.consider_all_requests_local
rescue_from ActionController::RoutingError, ActionController::UnknownController, ::AbstractController::ActionNotFound, ActiveRecord::RecordNotFound, with: lambda { |exception| render_error 404, exception }
end
private
def render_error(status, exception)
Rails.logger.error status.to_s + " " + exception.message.to_s
Rails.logger.error exception.backtrace.join("\n")
respond_to do |format|
format.html { render template: "errors/error_#{status}",status: status }
format.all { render nothing: true, status: status }
end
end
end
त्रुटियों को नियंत्रित करता है
class ErrorsController < ApplicationController
def error_404
@not_found_path = params[:not_found]
end
end
विचारों / त्रुटियों / error_404.html.haml
.site
.services-page
.error-template
%h1
Oops!
%h2
404 Not Found
.error-details
Sorry, an error has occured, Requested page not found!
You tried to access '#{@not_found_path}', which is not a valid page.
.error-actions
%a.button_simple_orange.btn.btn-primary.btn-lg{href: root_path}
%span.glyphicon.glyphicon-home
Take Me Home
मैं किसी भी लॉग इन करने वाले उपयोगकर्ता के लिए एक 'सामान्य' 404 फेंकना चाहता था जो कि कोई व्यवस्थापक नहीं है, इसलिए मैंने कुछ इस तरह से रेलिंग में लिखना समाप्त कर दिया:
class AdminController < ApplicationController
before_action :blackhole_admin
private
def blackhole_admin
return if current_user.admin?
raise ActionController::RoutingError, 'Not Found'
rescue ActionController::RoutingError
render file: "#{Rails.root}/public/404", layout: false, status: :not_found
end
end
routes.rb
get '*unmatched_route', to: 'main#not_found'
main_controller.rb
def not_found
render :file => "#{Rails.root}/public/404.html", :status => 404, :layout => false
end
त्रुटि से निपटने के परीक्षण के लिए, आप कुछ इस तरह से कर सकते हैं:
feature ErrorHandling do
before do
Rails.application.config.consider_all_requests_local = false
Rails.application.config.action_dispatch.show_exceptions = true
end
scenario 'renders not_found template' do
visit '/blah'
expect(page).to have_content "The page you were looking for doesn't exist."
end
end
यदि आप विभिन्न तरीकों से 404s को संभालना चाहते हैं, तो उन्हें अपने नियंत्रकों में पकड़ने पर विचार करें। यह आपको विभिन्न उपयोगकर्ता समूहों द्वारा उत्पन्न 404 की संख्या को ट्रैक करने जैसी चीजों को करने की अनुमति देगा, उपयोगकर्ताओं के साथ बातचीत करने के लिए यह पता लगाने में सहायता करेगा कि क्या गलत हुआ / उपयोगकर्ता अनुभव के किस हिस्से को ए / बी परीक्षण करना चाहिए, आदि।
मैंने यहाँ ApplicationController में आधार तर्क रखा है, लेकिन इसे केवल एक नियंत्रक के लिए विशेष तर्क रखने के लिए अधिक विशिष्ट नियंत्रकों में भी रखा जा सकता है।
कारण है कि अगर मैं ENV ['RESCUE_404'] के साथ प्रयोग कर रहा हूं, तो मैं AR :: RecordNotFound के अलगाव में परीक्षण कर सकता हूं। परीक्षणों में, मैं इस ईएनवी संस्करण को झूठे में सेट कर सकता हूं, और मेरे बचाव_फ्रेम में आग नहीं लगेगी। इस तरह मैं सशर्त 404 तर्क से अलग होने का परीक्षण कर सकता हूं।
class ApplicationController < ActionController::Base
rescue_from ActiveRecord::RecordNotFound, with: :conditional_404_redirect if ENV['RESCUE_404']
private
def conditional_404_redirect
track_404(@current_user)
if @current_user.present?
redirect_to_user_home
else
redirect_to_front
end
end
end