Help us understand the problem. What is going on with this article?

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

More than 5 years have passed since last update.

シングルページアプリケーションを書く時にいっつも似たようなコードを書いていたので、勢い余って 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とかメソッドとかを、ちゃんと本来の意味で使おうね' っていう運動だと理解しており、適切なステータスコードで結果を返すのもその方向性だろうと思って、この名前にしています。

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

https://github.com/kuboon/restful_error

heartrails
ハートレイルズは、新規事業の立ち上げに伴うウェブサービス、スマホアプリの企画、開発、運用に特化した開発会社です。
http://www.heartrails.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away