[ruby-on-rails] Rails에서 404로 리디렉션하는 방법은 무엇입니까?

Rails에서 404 페이지를 ‘가짜’로 만들고 싶습니다. PHP에서는 오류 코드가있는 헤더를 다음과 같이 보냅니다.

header("HTTP/1.0 404 Not Found");

Rails는 어떻게 되나요?



답변

404를 직접 렌더링하지 마십시오. 이유가 없습니다. Rails에는이 기능이 이미 내장되어 있습니다. 404 페이지를 표시하려면 다음 render_404not_found같이 메소드를 작성하십시오 (또는 호출 한대로) ApplicationController.

def not_found
  raise ActionController::RoutingError.new('Not Found')
end

또한 핸들 레일 AbstractController::ActionNotFoundActiveRecord::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 헤더를 반환하려면 :statusrender 메소드 의 옵션을 사용하십시오 .

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 오류 페이지로 렌더링하려는 페이지에 추가하면됩니다.