32
28

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Last updated at Posted at 2014-11-30

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

使い方

Gemfile
gem 'restful_error'

以上。

そうすると、

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

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

{ status_code: 404, response_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

http_status メソッドを定義して Helper を include する

class OAuthController < ApplicationController

  # all you need is status_code
  class RequireTwitterLogin < StandardError
    include RestfulError::Helper
    def http_status = :unauthorized # or 401 
  end
end

response のカスタマイズ

デフォルトで、 html, json, xml に応答する。
response_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 エラー汎用となる。

response_message は include Helper で追加されるが、メソッド定義を上書きするか、 @response_message に値を入れれば優先される 。

class RequireLogin < StandardError
  def initialize(provider = 'Unknown')
    @provider = provider
  end
  def http_status
    :unauthorized
  end
  def response_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 は http_status がなくてもここからステータスを取っており、
ActiveRecord::RecordNotFound ではちゃんと 404 になるし、 ActiveRecord::RecordInvalid ではちゃんと 422 になる。

ステータスコードのリストみたいなのどっかにないかなーと思ったら Rack::Util にあったのでそれを使ってます。
全てのステータスコードにシンボルが対応していて、数字でもシンボルでもどっちでも使えるようになっている。便利。

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

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?