blog.waterlow.work

Ruby, Rails, js, etc...

そもそもRailsでカスタム例外を定義すべき機会は少ない

はじめに

今仕事でRailsアプリケーションの運用をやっているのですが、いろいろなところで例外が定義されていて「これ必要なくね…」となんとなく思ったことが多々ありました。 しかし、effective rubyには「raiseにはただの文字列ではなくカスタム例外を渡そう」という章もあり、この違いはなんだろうと思いました。 なんでそう思ったのか整理して、今後自分のプログラミングに生かして行こうと思います。まとめると以下になります。

  • カスタム例外を自分でraiseしてrescueするな。戻り値で判断しろ。

よく見るコード

Resourceモデル

class Resource
  Error = Class.new(StandardError)
  def write
    # 何かの処理
    result = false # 何かの処理の結果falseだったと仮定
    raise Error, '保存時にエラーが発生しました。'
  end
end

Resourcesコントローラ

class ResourcesController < ApplicationController
  def create
    Resource.new.write
    redirect_to '/', flash: { notice: '作成されました' }
  rescue Resource::Error => e
    redirect_to '/', flash: { error: e.message }
  end
end

よく見るコードがあまり良くない理由

汎用性も可読性も低い。一般的でもないということですね…。

どうすればいいか

Resourceモデル

class Resource
  def write
    # 何かの処理
    false # 何かの処理の結果falseだったと仮定
  end
end

Resourcesコントローラ

class ResourcesController < ApplicationController
  def create
    if Resource.new.write
      redirect_to '/', flash: { notice: '作成されました' }
    else
      redirect_to '/', flash: { error: '作成されませんでした' }
    end
  end
end

カスタム例外は必要なくなりましたし、表示用のメッセージがモデルに縛られなくなりました。

結局カスタム例外は必要ないの?

必要ないとは言いませんが、単体のRailsアプリケーションを書いている場合、自分でraiseしようとしている例外はそもそもシステムエラーではなく業務エラー(日常的におこりうる)であることが多いように思いました。 もしそれがシステムエラーならば、rescueして握りつぶしては検知できないですし、そうなるとrescueしないんだからカスタム例外ではなくてもいいよねという話になると思い、最終的に独自例外いらないよねということになるんじゃないかなと思います。。。

gemなど不特定多数の人が使うものに関しては積極的に定義していくべきだと思います。gemから返ってくる例外がRuntimeErrorだとつらいですしね。

まとめ

やっぱりRailsでカスタム例外を定義すべき機会は少ないし、少なくとも自分はめったにやらないかなと思いました。