Rails에서 404 페이지를 ‘가짜’로 만들고 싶습니다. PHP에서는 오류 코드가있는 헤더를 다음과 같이 보냅니다.
header("HTTP/1.0 404 Not Found");
Rails는 어떻게 되나요?
답변
404를 직접 렌더링하지 마십시오. 이유가 없습니다. Rails에는이 기능이 이미 내장되어 있습니다. 404 페이지를 표시하려면 다음 render_404
과 not_found
같이 메소드를 작성하십시오 (또는 호출 한대로) ApplicationController
.
def not_found
raise ActionController::RoutingError.new('Not Found')
end
또한 핸들 레일 AbstractController::ActionNotFound
과 ActiveRecord::RecordNotFound
같은 방법으로.
이것은 두 가지 일을 더 잘합니다.
1) Rails의 내장 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 render 404의 추가 정보를 컨트롤러 작업에서 찾을 수 없습니다.
답변
HTTP 404 상태
404 헤더를 반환하려면 :status
render 메소드 의 옵션을 사용하십시오 .
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
조치가 오류 페이지를 렌더링하고 중지하도록하려면 단순히 return 문을 사용하십시오.
def action
render_404 and return if params[:something].blank?
# here the code that will never be executed
end
ActiveRecord 및 HTTP 404
또한 Rails ActiveRecord::RecordNotFound
는 404 오류 페이지 표시 와 같은 일부 ActiveRecord 오류를 복구합니다 .
그것은 당신이이 행동을 스스로 구출 할 필요가 없다는 것을 의미합니다
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
수표를 Rails에 위임하여 단순화 할 수 있습니다. 뱅 버전을 사용하십시오.
def show
user = User.find_by_email!(params[:email])
# ...
end
답변
Steven Soroka가 제출 한 새로 선택된 답변은 가깝지만 완료되지 않았습니다. 테스트 자체는 이것이 실제 404를 반환하지 않는다는 사실을 숨 깁니다. 200- “성공”상태를 반환합니다. 원래의 대답은 더 가까웠지만 실패가없는 것처럼 레이아웃을 렌더링하려고 시도했습니다. 이것은 모든 것을 고친다 :
render :text => 'Not Found', :status => '404'
다음은 RSpec 및 Shoulda 매처를 사용하여 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/
참고 : 컨트롤러에서 발생하는 일 (예 : “should_raise”)에 대한 테스트는 권장하지 않습니다. 관심있는 것은 출력입니다. 위의 테스트를 통해 다양한 솔루션을 시도 할 수 있었고 솔루션이 예외, 특수 렌더링 등을 발생시키는 지 여부와 상관없이 테스트는 동일하게 유지됩니다.
답변
렌더 파일을 사용할 수도 있습니다.
render file: "#{Rails.root}/public/404.html", layout: false, status: 404
레이아웃 사용 여부를 선택할 수 있습니다.
다른 옵션은 예외를 사용하여 예외를 제어하는 것입니다.
raise ActiveRecord::RecordNotFound, "Record not found."
답변
오류 처리기가 미들웨어로 이동함에 따라 선택한 답변이 Rails 3.1 이상에서 작동하지 않습니다 ( github issue 참조 ).
내가 찾은 해결책은 다음과 같습니다.
에서 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
이것은 확실히 개선 될 수 있지만 적어도 핵심 Rails 함수를 재정의하지 않고 not_found 및 internal_error에 대한 다른 견해를 가지고 있습니다.
답변
이것들이 당신을 도울 것입니다 …
어플리케이션 컨트롤러
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
views / errors / 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
답변
<%= render file: 'public/404', status: 404, formats: [:html] %>
404 오류 페이지로 렌더링하려는 페이지에 추가하면됩니다.