LoginSignup
94
64

More than 5 years have passed since last update.

to_json で関連モデルなどを含む複雑なオブジェクトを出力する

Last updated at Posted at 2018-10-09

はじめに

Rails のモデルには to_json という便利なメソッドがあります。このメソッドはデフォルトでは、すべてのカラムとその値を含む json 文字列を返します。ただ、値を少し加工したい場面がほとんどです。たとえば下記のような要求が出てくると思います。

  • 特定のカラムを出力しないようにする
  • 特定のカラムだけを出力する
  • メソッドの結果をカラムのようにして出力する
  • 関連モデルを出力する
  • 関連モデルの特定カラムを出力する or 特定カラムを出力しない
  • 関連モデルのさらに関連モデルを出力する

上記のことを実現するのに to_json の呼び出し先の as_json をオーバーライドする方法や、独自メソッドを定義する方法、 jbuilder を使う方法などが紹介されているようです。しかしながら、上記の要求であれば to_json のオプションだけで実現できます。

基本

以降は Book というモデルを例にして紹介していきます。 to_json はモデルに定義されているほか、リレーションにも定義されています。

Book.first.to_json
Book.all.to_json

特定のカラムを出力しないようにする

オプションの except を使います。たとえば id と body を出力しない場合は下記のようにします。例では配列を引数にしていますが、要素数が1個の場合は配列の中身を直接指定できます。以降のメソッドも同様です。

Book.first.to_json(except: [:id, :body])

特定のカラムだけを出力する

オプションの only を使います。たとえば title だけを出力したい場合は下記のようにします。

Book.first.to_json(only: [:title])

メソッドの結果をカラムのようにして出力する

オプションの methods を使います。たとえば Book に要約を出力するインスタンスメソッド summary が定義されている場合は下記のようにします。

Book.first.to_json(methods: [:summary])
Book.first.to_json(methods: [:summary], only: [:summary]) # summary 以外出力しない

関連モデルを出力する

オプションの include を使います。たとえば Book に belongs_to の関連モデル Author, Publisher が定義されている場合は下記のようにします。has many 関係でも同様にできます。 has many through の関係でも同様です。

Book.first.to_json(include: [:author, :publisher])

関連モデルの特定カラムを出力する or 特定カラムを出力しない

オプションの include を使います。そして include 先のモデルにもオプションを与えます。たとえば、上記の例において Publisher モデルの名前 name 以外のカラムが不要な場合は下記のようにします。

Book.first.to_json(include: [:author, {publisher: {only: :name}}])

例は省略しますが except も同じように使うことができます。

関連モデルのさらに関連モデルを出力する

オプションの include を使います。そして include 先のモデルにもオプションを与えます。たとえば、 Book -> Author -> Group の順に has one 関連モデルを持っていて、その階層関係すべてを出力する場合は下記のようにします。

Book.first.to_json(include: {author: {include: :group}})

まとめ

to_json のオプション引数を使って、いろいろな要求が実現できることを紹介しました。オプション only, except, method, include, はすべて組み合わせ可能です。たとえば下のような複雑なオプションを与えることができます。

Book.all.to_json(
  only: [], # Book のカラムはすべて不要
  include: {
    publisher: {} # Publisher のオプションは無し(デフォルトで出力)
    author: {
      include: {
        group: { # Group は group_name メソッドの結果だけ出力
          methods: :group_name
          only: :group_name
        }
      }
    }
  }
)

可読性や実行速度、再利用性を重視する場合は Jbuilder や Fast JSON APIjsonapi-rb などを使うべきかもしれません。

94
64
0

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
94
64