sourcecode

레일즈에서 404로 리디렉션하는 방법은 무엇입니까?

copyscript 2023. 6. 8. 22:27
반응형

레일즈에서 404로 리디렉션하는 방법은 무엇입니까?

저는 레일즈에서 404페이지를 '가짜'하고 싶습니다.PHP에서는 다음과 같은 오류 코드가 포함된 헤더를 보냅니다.

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

레일즈는 어떻게 된 거지?

직접 렌더링하지 그럴 이유가 이 이 내장되어 . 404 접직지하마십시오링더렌를마▁don. Rails에는 이미 이 기능이 내장되어 있습니다.404페이지를 , 404페이지를 .render_404또는 또방법(는)not_found내가 말한 바와 같이)에ApplicationController와 같이: 과같이다음:

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

레도핸링을 합니다.AbstractController::ActionNotFound,그리고.ActiveRecord::RecordNotFound같은 방법.

이렇게 하면 다음과 같은 두 가지 작업을 더 잘 수행됩니다.

레일즈의 내장 기능을 사용합니다.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

또는 컨트롤러 작업에서 레일 렌더 404의 자세한 정보를 찾을없습니다.

HTTP 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

액티브레코드와 HTTP 404

Rails는 "Rails" "ActiveRecord"와 오류를 합니다.ActiveRecord::RecordNotFound404 오류 페이지를 표시합니다.

당신이 직접 이 행동을 구출할 필요가 없다는 뜻입니다.

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

Steven Soroka가 제출한 새로 선택한 답변이 가깝지만 완료되지 않았습니다.테스트 자체는 이것이 진정한 404를 반환하지 않는다는 사실을 숨깁니다. 즉, 200 - "성공" 상태를 반환합니다.원래 답변은 더 가까웠지만 실패가 발생하지 않은 것처럼 레이아웃을 렌더링하려고 시도했습니다.이렇게 하면 모든 문제가 해결됩니다.

render :text => 'Not Found', :status => '404'

다음은 RSpec 및 Shoulda matchers를 사용하여 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 문제 참조).

여기 제가 찾은 해결책이 있습니다. 제가 꽤 만족하는 것이죠.

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

보기/오류/오류_404.208.햄

.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
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
<%= render file: 'public/404', status: 404, formats: [:html] %>

이것을 404 오류 페이지에 렌더링할 페이지에 추가하기만 하면 완료됩니다.

저는 관리자가 아닌 로그인한 사용자를 위해 '일반' 404를 던지고 싶었습니다. 그래서 저는 Rails 5에 다음과 같습니다.

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

ActionController::RoutingError('not found')인증되지 않은 사용자의 경우 이 오류는 현실을 반영하지 않습니다. 경로가 발견되었고 사용자가 인증되지 않았습니다.

우연히 알게 되었고 어떤 경우에는 이것이 언급된 문제에 대한 보다 우아한 해결책이라고 생각합니다.

# application.rb
config.action_dispatch.rescue_responses = {
  'UnauthenticatedError' => :not_found
}

# my_controller.rb
before_action :verify_user_authentication

def verify_user_authentication
  raise UnauthenticatedError if !user_authenticated?
end

이 접근 방식의 장점은 다음과 같습니다.

  1. 오류 처리 미들웨어처럼 .ActionController::RoutingError에서 더 있는 .
  2. rescue_response 해시에서 지정한 대로 상태를 올바르게 설정합니다(이 경우 404 - not_found).
  3. 당신은 그것을 쓸 필요가 없습니다.not_found모든 곳에서 사용할 수 있어야 하는 방법.

오류 처리를 테스트하려면 다음과 같은 작업을 수행할 수 있습니다.

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

다양한 404를 다양한 방식으로 처리하려면 컨트롤러에서 이를 파악하는 것이 좋습니다.이를 통해 서로 다른 사용자 그룹에서 생성된 404개의 수를 추적하고, 지원팀이 사용자와 상호 작용하여 무엇이 잘못되었는지, 사용자 환경의 어떤 부분을 조정해야 하는지, A/B 테스트 등을 수행할 수 있습니다.

여기에서는 기본 논리를 Application Controller에 배치했지만, 특정 컨트롤러에 배치할 수도 있으므로 컨트롤러 하나에 대한 특수 논리를 가질 수도 있습니다.

ENV와 함께 if를 사용하는 이유['RESCURE_404'], AR의 상승을 테스트할 수 있습니다.:RecordNotFound가 분리되어 있습니다.테스트에서 이 ENV 변수를 false로 설정할 수 있으며 rescue_from이 실행되지 않습니다.이렇게 하면 조건부 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

언급URL : https://stackoverflow.com/questions/2385799/how-to-redirect-to-a-404-in-rails

반응형