91
56

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Active Model Serializer をざっくり使ってみた

Posted at

#はじめに
Railsのプロジェクトで一部json形式でデータをレスポンスを返す必要があった時、インスタンス変数をメソッドで無理やりjsonにして関連付けレコードはmergeで無理やり連結、といった力技でコードを書いていました。
しかし、Active Model Serializerというgemを使えば簡単にjsonデータを整形できるとのことだったので試してみました。

#環境

ruby '2.5.1'
rails '5.2.4.1'
active_model_serializers '0.10.10'

#使用するモデル、アソシエーション

project.rb
class Project < ApplicationRecord
  has_many :jobs, dependent: :destroy
  has_many :project_categories, dependent: :destroy
  has_many :categories, through: :project_categories
end
job.rb
class Job < ApplicationRecord
  belongs_to :project
end
project_category.rb
class ProjectCategory < ApplicationRecord
  belongs_to :project
  belongs_to :category
  
end

#Active Model Serializerの設定

以下のコマンドでModelに紐づくSerializerのファイルを作成できる

rails g serializer "モデル名"

まずはJobのserializerファイルを設定してみる

jobs_serializer.rb
class JobSerializer < ActiveModel::Serializer
  # 出力したいカラムを指定
  attributes :id, :name
end

#Jsonを出力

コントローラに以下のコードを記述

jobs_controllers.rb
  def index
    @job = Job.first
    render json: @job, serializer: JobSerializer
  end

出力結果

{
  "id": 1,
  "name": "ジョブ1"
}

期待した値が帰ってきました!

#複数のデータを出力する

1つのデータだけではなく複数のデータを出力したい場合は以下のようにコード記述

jobs_controllers.rb
  def index
    @jobs = Job.all
    render json: @jobs, each_serializer: JobSerializer
  end

出力結果

[
  {
    "id": 1,
    "name": "ジョブ1"
  },
  {
    "id": 2,
    "name": "ジョブ2"
  },
  {
    "id": 3,
    "name": "ジョブ3"
  }
]

#ネストしたデータを出力する

Jobの親であるProjectも一緒に表示してみる

Projectのserializerファイルを下記のように設定

projects_serializer.rb
class ProjectSerializer < ActiveModel::Serializer
  # 出力したいカラムを指定
  attributes :id, :name
end

Jobのserializerファイルを下記のコードに修正

jobs_serializer.rb
class JobSerializer < ActiveModel::Serializer
  # 出力したいカラムを指定
  attributes :id, :name

  # アソシエーションの指定
  belongs_to :project,  serializer: ProjectSerializer
end

ネストされたデータを出力するとN+1問題が発生するので、controller側で下記のようにコードを修正

jobs_controllers.rb
  def index
    # N+1問題の対応
    @jobs = Job.preload(:project)

    render json: @jobs, each_serializer: JobSerializer
  end

出力結果

[
  {
    "id": 1,
    "name": "ジョブ1",
    "project": {
      "id": 1,
      "name": "テスト1"
    }
  },
  {
    "id": 2,
    "name": "ジョブ2",
    "project": {
      "id": 2,
      "name": "テスト2"
    }
  },
  {
    "id": 3,
    "name": "ジョブ3",
    "project": {
      "id": 3,
      "name": "テスト2"
    }
  }
]

#多重ネストしたデータを出力する

次はProjectと多対多の関係であるCategoryを表示してみる

Cagegoryのserializerファイルを下記のように設定

categories_serializer.rb
class CategorySerializer < ActiveModel::Serializer
  # 出力したいカラムを指定
  attributes :id, :name
end

Projectのserializerファイルを下記のように修正

projects_serializer.rb
class ProjectSerializer < ActiveModel::Serializer
  # 出力したいカラムを指定
  attributes :id, :name

  # アソシエーションの指定
  has_many :categories,  serializer: CategorySerializer
end

出力結果

[
  {
    "id": 1,
    "name": "ジョブ1",
    "project": {
      "id": 1,
      "name": "テスト1"
    }
  },
  {
    "id": 2,
    "name": "ジョブ2",
    "project": {
      "id": 2,
      "name": "テスト2"
    }
  },
  {
    "id": 3,
    "name": "ジョブ3",
    "project": {
      "id": 3,
      "name": "テスト2"
    }
  }
]

Categoryがネストされていない。。。
どうやら多重ネストを出力したい場合は、render時にincludeオプションを設定してあげる必要があるようです。

Jobのcontrollerを下記のように修正

jobs_controllers.rb
  def index
    # N+1問題の対応
    Job.preload(project: [:categories])

    render json: @jobs, each_serializer: JobSerializer, include: { project: [ :categories] }
  end

出力結果

[
  {
    "id": 1,
    "name": "ジョブ1",
    "project": {
      "id": 1,
      "name": "テスト1",
      "categories": [
        {
          "id": 1,
          "name": "北海道"
        },
        {
          "id": 2,
          "name": "東北"
        },
        {
          "id": 5,
          "name": "甲信越"
        }
      ]
    }
  },
  {
    "id": 2,
    "name": "ジョブ2",
    "project": {
      "id": 2,
      "name": "テスト2",
      "categories": [
        {
          "id": 7,
          "name": "東海"
        },
        {
          "id": 8,
          "name": "関西"
        },
        {
          "id": 9,
          "name": "中国3"
        },
        {
          "id": 10,
          "name": "四国"
        },
        {
          "id": 11,
          "name": "九州・沖縄"
        }
      ]
    }
  },
  {
    "id": 3,
    "name": "ジョブ3",
    "project": {
      "id": 3,
      "name": "テスト3",
      "categories": [
        {
          "id": 4,
          "name": "首都圏"
        },
        {
          "id": 6,
          "name": "北陸"
        },
        {
          "id": 8,
          "name": "関西"
        },
        {
          "id": 9,
          "name": "中国"
        }
      ]
    }
  },
]

無事多重ネストしたデータを出力できました!

#参考URL
https://github.com/rails-api/active_model_serializers/blob/v0.10.6/docs/general/configuration_options.md
https://tech.medpeer.co.jp/entry/2018/04/25/080000
https://techracho.bpsinc.jp/hachi8833/2017_09_28/45536
https://qiita.com/unasaka/items/08659477c72656df02e8
https://qiita.com/romukey/items/b78906e91a0355e1e77a
https://qiita.com/kakkunpakkun/items/1c23b936d13f08a42752
https://qiita.com/rh_taro/items/b09b3ebb68c2566c1ee5

91
56
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
91
56

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?