webエンジニアさもの挑戦

RubyやPython, JSなど、IT関連の記事を書いています

Rails入門者のためのQA~例外処理~

f:id:s-uotani-zetakansu:20171128150634j:plain

こんにちは、エンジニアのさもです。

2回目にしていきなり例外処理です。しかもQAじゃないです(笑)

入門したては、ガンガン機能を追加していき、サイトを作りこんで行きたいかと思うのですが、少し立ち止まって、例外処理について学んで下さい。

一度書くと、次に作るときにコピペでOKです!

スポンサーリンク

目次

Railsにおける例外処理とは?

Javaなどのプログラミング言語でも例外を投げる、キャッチする。なんて言いますよね。

Rubyにもraise, rescueという例外に関する仕様はあるのですが、今回はRailsで例外発生時の挙動をどうするか、について書いていきます。

webサイトを良く見る方は、「404 Not Found」みたいなページを見たことがあるでしょうか?URLが間違っていたり、久しぶりに訪れたらサイトが無くなっていたなんてときに表示されるページです。

「404」というのはwebページへアクセスしたときに、コンテンツと一緒についてくる、「HTTPステータスコード」の一つです。

正常にページが見れるときは、200が割り当てられています。サーバに障害があったときは、500が返ってきたりします。

詳しくはこちら

404はただのコードなので、webページの場合は、返ってきてもどうしようもないですよね。だから404ページと言われるものを返します。

自分でwebサイトを作るときも、間違ったURLにアクセスされたとき用に404ページは作っておかなければなりません。

それ以外に、例えば、/users/1 のように、idが1のユーザにアクセスするURLがあるとします。このとき、存在しないユーザーIDへアクセス(/users/999)した場合にも404ページを返さなくてはいけません。

なぜなら、RailsはRestful、つまりURLとリソースが1対1で結びついているからです。リソースというと、/views/users/show.html.erbのことを思い浮かべるかもしれませんが、実際は、「idが1のユーザー」の事を指しています。htmlファイルはあくまでも、リソースを見やすく整形したものです。

そのため、「/users/存在しないユーザーID」にアクセスされたときは、対応するリソース(ユーザー)が存在しないので、ページが存在しないという情報を返さなくてはなりません。この情報が、404ページであり、ステータスコード404です。

例外の発生方法

例外処理の基本は、例外が発生(raise)ー>例外をキャッチ(rescue)です。

まずは例外の発生について書いていきましょう。

具体的にどのように実装するのか、ですが、実はとても簡単です。

最も基本的な例ですが、UsersController#showで、存在しないユーザIDが指定された場合について考えましょう。

class UsersController < ApplicationController
  before_action :set_user, only: [:edit, :update, :show, :destroy]
  # index等省略
  def show
  end

  private

  def set_user
    @user = User.find(params[:id])
  end
end

はい、完了です。

いつもどおりのコントローラですね。

どこで例外が発生するかわかりますか?

正解は、findメソッドです。

findメソッドは、引数で渡したIDのユーザが存在しない場合に、ActiveRecord::RecordNotFoundという名前の例外を発生させます。

試しに、rails consoleで「User.find(999)」と打ってみてください(モデルはお使いの環境に合わせて、存在しているモデルに変えてください)。ActiveRecord::RecordNotFoundと表示されるはずです。

例外のキャッチの仕方

何もしません(笑)

404エラーや500, 422エラーの場合は、Railsがよしなにやってくれます。

表示されるエラーページ自体はpublicフォルダにあります。

ただし、デフォルトのエラーページは味気ないので、かっこよくカスタマイズしたい場合は、public/404.htmlなど、対応するhtmlファイルを編集すればOKです。

自分で例外を発生させる

ActiveRecord::RecordNotFoundの場合には自動的に例外を投げてくれましたが、「自分のサイトではこういう場合に404を発生させて、404ページを表示したいんだ」ということがあります。

そんなときは以下のようにします。(例えば、ユーザのemailカラムが未入力の場合に、まだユーザが存在していないかのように見せたいとき。)

class UsersController < ApplicationController
  before_action :set_user, only: [:edit, :update, :show, :destroy]
  # index等省略
  def show
    raise ActiveRecord::RecordNotFound.new("お試し例外だよ") if @user.email.nil?
  end

  private

  def set_user
    @user = User.find(params[:id])
  end
end

showアクションに1行追加しました。

raiseメソッドは、第一引数の例外を発生させるKernelクラスのメソッドです。

ちなみに、raiseメソッドに文字列を渡すと、その文字列をメッセージとしたRuntimeError例外を発生させます。

すべての例外に対応する

ActiveRecord::RecordNotFoundをはじめ、例外はたくさんあります。そこで、用意している例外以外の例外に対応するために、 復旧可能な実行時エラーの親クラスである、StandardErrorに対してrescueします。

エラーキャッチの定義は、application_controller.rbに書きます。

class ApplicationController < ActionController::Base

  rescue_from StandardError, with: :rescue_exeption

  def rescue_exeption(e = nil)
    if e
      logger.info "StandardError!: #{e.message}"
      logger.info e.backtrace.join("\n")
    end
    redirect_to root_path
  end
end

このように書いておくと、Railsが拾わなかった例外を、rescue_exeptionメソッドが処理してくれるようになります。rescue_exeption内では、エラー原因特定やデバッグのために、出来るだけ多くの情報を残しましょう。

Bagsnagというサービスを利用して、開発者へ通知するなどの処理を含めるのも有効です。

参考

より詳しく勉強したいという方のために、オススメの書籍を紹介します

  • ステータスコードやURLをどう設計するかなど、Rialsでも役に立つ知識がいっぱい載っています。

Webを支える技術 -HTTP、URI、HTML、そしてREST (WEB+DB PRESS plus)

Webを支える技術 -HTTP、URI、HTML、そしてREST (WEB+DB PRESS plus)

  • 定評のあるRails本

Ruby on Rails 5アプリケーションプログラミング

Ruby on Rails 5アプリケーションプログラミング

Ruby on Rails 4 アプリケーションプログラミング

Ruby on Rails 4 アプリケーションプログラミング

  • 最近出たRubyの本(チェリー本)すごくいい!先行販売してたので買いました。

  • Railsの例外について、とてもよくまとまっているエントリーです。

qiita.com

最後に

以上、Railsの例外処理でした。

いかなるユーザの操作に対しても応答できるwebサービスを目指して、ぜひ例外処理を書いてみてください。

読者登録をしていただけると、ブログを続ける励みになりますので、よろしくお願いします。