たばりばりスタイル

たばりばりスタイル

バリバリバリ⚡︎

ActionController::Renderers.add で render_xxx メソッドを撃退

Railsで開発している際、コントローラー内で render_xxx のような独自メソッドをよく見かけます。特に API を構築する際に、render_api や render_json などのレスポンス構成を共通化するために、render json: の処理をラップしたコードをよく目にします。

以下のようなコードです。実際には内部で別のプライベートメソッドを呼び出すなど、複雑な実装が含まれていることもあります。

# api を返すときはこのメソッドを使う ← よく見るコメント
def render_api(object, status: 200)
  render json: {
    data: object,
    status: status
  }
end

# 利用部分
render_api(record, status: 200)

# json レスポンス
# {"data":{"id":1,"created_at":xxx,"updated_at":xxx,"name":"john"},"status":200}

しかしこのアプローチには何か違和感があります。特には複数のプライベートも重ねて実行されることもあり、無駄に application_controller のようなベースコントローラにつらつらと書かれていることも多く、見てて気持ちいい実装ではありませんでした。
常に同じ形式で使用するのであれば、render api: xxx のようなシンタックスがよりスマートであると感じるのではと。

ActionController::Renderers.add による改善

この違和感を解消するための方法として、 ActionController::Renderers.add で renderer を追加するやり方があります。
これを導入することで、render hoge: xxx のような記述でレスポンスを返すことができるようになります。

# config/initializers/add_controller_renderer.rb

ActionController::Renderers.add :api do |object, options|
  json_response = {
    data: object,
    status: options[:status] || 200
  }
  render json: json_response, status: json_response[:status]
end

上記のコードを追加するだけで、以下のようにレスポンスを生成できます。

# コントローラ内で下記のように利用可能
render api: record, status: 200

# json レスポンス
# {"data":{"id":1,"created_at":xxx,"updated_at":xxx,"name":"john"},"status":200}

個人的にはこっちの方がより Rails チックでスマートな記述に感じます。 このアプローチを取ることで、独自のレンダリングメソッドをコントラーラ内部につらつらと追加する必要もなくなります。

api のレスポンスの他にも react 描画用の html などのテンプレ形式で返す際にも便利なのでおすすめです。