LoginSignup
32
28

More than 5 years have passed since last update.

gem 'restful_error' をリリースしました

Last updated at Posted at 2014-11-30

シングルページアプリケーションを書く時にいっつも似たようなコードを書いていたので、勢い余って gem にしました。

使い方

Gemfile
gem 'restful_error'

って書いて、

application_controller.rb
class ApplicationController < ActionController::Base

  include RestfulError::ActionController

って書いておく。
そうすると、

def show
  @post = Post.find(param[:id])
end

みたいなアクションがあったとして、 GET /posts/10.json すると

{ status_code: 404, message: "要求されたリソースが存在しません"}

みたいに json がちゃんと返ってくる。(もちろん status code は404)
他のステータスも自由に raise できる。

class PostsController < ApplicationController
  before_action do
    raise RestfulError[401] unless current_user
    # or
    raise RestfulError::Unauthorized unless current_user
  end
end

自分でエラーを定義する時は、継承するか

class ::NoSession < RestfulError[404]; end
# or
class ::NoSession < RestfulError::NotFound; end

status_code メソッドを定義しておく (duck typing)

class OAuthController < ApplicationController

  # all you need is status_code
  class RequireTwitterLogin < StandardError
    def status_code; 401; end
  end
  # or
  class RequireTwitterLogin < StandardError
    def status_code; :unauthorized; end
  end
end

response のカスタマイズ

デフォルトで、 html, json, xml に応答する。
message のとこは

config/locales/restful_error.yml
ja:
  restful_error:
    active_record/record_not_found: 要求されたリソースが存在しません
    not_found: ページが存在しません

で設定可能。
active_record/record_not_foundActiveRecord::RecordNotFound 専用、 not_found は 404 エラー汎用となる。

status_message というメソッドがある場合にはそれを優先する。

class RequireLogin < StandardError
  def initialize(provider = 'Unknown')
    @provider = provider
  end
  def status_code
    :unauthorized
  end
  def status_message
    I18n.t('restful_errors.require_login', provider: provider)
  end
end

以下のいずれかを置いておけば、レスポンスを柔軟にカスタマイズ出来る。

  • views/restful_error/show.html.erb
  • views/restful_error/show.json.jbuilder
  • views/restful_error/show.xml.erb

(もちろん haml でも rabl でもそこはご自由に)

中身の話

ActiveRecord::RecordNotFound が raise された時にステータスコードがちゃんと 404 になる仕組みが Rails にもともとあって、これは config/application.rb とかで

config.action_dispatch.rescue_responses.merge!(
  'MyGreatError'   => :not_found,

としておくと、 raise MyGreatError で 404 を返してくれる。
resutful_error は rescue_responses に値を追加しないが、既に追加されているものについては参照している。なので、 ActiveRecord::RecordNotFound ではちゃんと 404 になるし、 ActiveRecord::RecordInvalid ではちゃんと 422 になる。

ステータスコードのリストみたいなのどっかにないかなーと思ったら標準ライブラリの webrick の中に綺麗に定義されてた。
https://github.com/ruby/ruby/blob/trunk/lib/webrick/httpstatus.rb
これ、 Webrick の中に入っちゃってるのもったいないなーと思い、引っ張りだして使っています。
全てのステータスコードにシンボルが対応していて、数字でもシンボルでもどっちでも使えるようになっている。便利。

例外には message メソッドがあるのだけどこれは i18n に対応していないので使用しない。クラス名、 reason phrase (404 なら not_found みたいなやつ) の順に i18n のキーを検索して適用することにしている。

開発の邪魔にならないように、(config.consider_all_requests_local = true) の場合 status_code が 500 のエラーは処理せず raise している。

FAQ

どこがrestfulやねん

すいません、誇大広告です。
いちおう気持ちとしては、'RESTってhttpのURLとかメソッドとかを、ちゃんと本来の意味で使おうね' っていう運動だと理解しており、適切なステータスコードで結果を返すのもその方向性だろうと思って、この名前にしています。

ツッコミをお待ちしております

32
28
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
32
28