読者です 読者をやめる 読者になる 読者になる

Rails Webook

自社のECを開発している会社で働いています。Rails情報やサービスを成長させる方法を書いていきます

Railsでrescue_fromメソッドを使ってエラーハンドリングをする方法

運用 エラーハンドリング

運用をしていくと、Railsアプリケーション内で例外が発生した場合に、適切な例外処理をする必要があります。
Railsでは、コントローラー内にrescue_fromメソッドを使って、例外をキャッチし例外処理を記述することが一般的です。

確認環境

  • Ruby 2.1.2
  • Rails 4.1

目次

  1. Railsプロジェクトの作成
  2. エラーハンドリング処理の追加
  3. エラーハンドリング処理の確認

1. Railsプロジェクトの作成

まずはRailsプロジェクトを作成します。

rails new error_handling_test
cd error_handling_test

次にエラーハンドリングの挙動を確認するために、PostをScaffoldで作成します。

rails g scaffold Post title:string content:text
rake db:migrate

2. エラーハンドリング処理の追加

では、Railsにエラーハンドリングを追加していきましょう。

まず、ApplicationControllerにエラーハンドリング処理を追加します。
rescue_fromメソッドにより、アプリケーション内のException(例外)をキャッチし、適切な処理をさせるという流れです。

# app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :exception

  # 他のエラーハンドリングでキャッチできなかった場合に
  # 500 Internal Server Error(システムエラー)を発生させる
  # NOTE: rescue_from は下から評価されるので記載箇所はここが正解
  rescue_from Exception, with: :handle_500 unless Rails.env.development?

  # 例外に合わせたエラーハンドリング
  # 404 Not Found リソースが見つからない。アクセス権がない場合にも使用される
  rescue_from ActionController::RoutingError, with: :handle_404 unless Rails.env.development?
  rescue_from ActiveRecord::RecordNotFound,   with: :handle_404 unless Rails.env.development?
  #rescue_from ActiveRecord::RecordNotUnique, with: :render_409
  #rescue_from UnauthorizedError,             with: :render_401
  #rescue_from IllegalAccessError,            with: :render_403

  # エラーハンドリング処理
  def handle_500(exception = nil)
    logger.info "Rendering 500 with exception: #{exception.message}" if exception

    if request.xhr?
      # Ajaxのための処理
      render json: { error: '500 error' }, status: 500
    else
      render template: 'errors/error_500', status: 500, layout: 'application', content_type: 'text/html'
    end
  end

  def handle_404(exception = nil)
    logger.info "Rendering 404 with exception: #{exception.message}" if exception

    if request.xhr?
      # Ajaxのための処理
      render json: { error: '404 error' }, status: 404
    else
      render template: 'errors/error_404', status: 404, layout: 'application', content_type: 'text/html'
    end
  end

end


次に、エラーハンドリング時に表示させるビューを作成します。

500エラー時のビューです。

# app/views/errors/error_500.html.erb
システムエラーが発生しました。<br />
管理者にご連絡してください。

404エラー時のビューです。

# app/views/errors/error_404.html.erb
ご指定になったページは存在しません。


ルーティングに定義されていなURLの場合、エラーはRack MIddlewareで発生するので、rescue_fromメソッドでキャッチできません。
そのため、ルーティング設定の最後にすべてのURLをキャッチするようにして対応します。

# config/routes.rb

Rails.application.routes.draw do
  resources :posts

  root "posts#index"

  match "*path" => "application#handle_404", via: :all
end

これでエラーハンドリングの実装は完了です。




3. エラーハンドリング処理の確認

では、productionモードでサーバーを起動させ、エラーハンドリング処理の確認をしましょう。
productionモードでのサーバーの起動方法は、こちら


localhost:3000にアクセスしましょう。
f:id:nipe880324:20141108151607p:plain:w480


では、Postを作成してましょう。問題なく登録できます。
f:id:nipe880324:20141108151634p:plain:w480


次に、URLを適当な値にし、存在しないIDにアクセスしてみましょう。404エラー画面に遷移します。
f:id:nipe880324:20141108151717p:plain:w480


また、存在しないURLにアクセスした場合も、404エラーが発生します。
f:id:nipe880324:20141108151737p:plain:w480


最後に、シンタックスエラーなどにし、サーバーを再起動しアクセスすると、500エラーが発生します。
f:id:nipe880324:20141108151757p:plain:w480


以上です。