1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

RailsのActiveModelSerializer vs Jbuilder使い分け|AI実務ノート 編集部

1
Last updated at Posted at 2026-01-03

1. 結論(この記事で得られること)

この記事を読むと、以下が明確になります。

  • ActiveModelSerializerとJbuilderの使い分け基準が実務レベルで判断できる
  • それぞれの落とし穴とパフォーマンス特性を理解し、レビューで指摘できる
  • AIを使って既存コードの変換やテスト生成を10倍速で進められる
  • 実際のプロダクトで起きた失敗事例から学べる

私自身、最初のプロジェクトでは「なんとなくJbuilderを使っていた」んですが、APIが複雑化してきたタイミングで地獄を見ました。この記事では、そういった痛みを避けるための実践知識を凝縮してお届けします。

2. 前提(環境・読者層)

想定環境

  • Rails 7.x系(6.x系でも大半は適用可能)
  • active_model_serializers gem 0.10.x
  • JSON API が中心のプロダクト

想定読者

  • Railsで API 開発を担当している
  • Serializer層の設計に悩んでいる
  • 既存のJbuilderをリファクタリングしたい、または逆にAMSから移行を検討している
  • レビュアーとして設計判断の根拠を示したい

3. Before:よくあるつまずきポイント

3-1. 「どっち使えばいいの?」問題

まず多くの人がハマるのがここ。Railsには標準でJbuilderが入ってるので、なんとなくそのまま使い始めがちです。

# app/views/api/users/show.json.jbuilder
json.id @user.id
json.name @user.name
json.email @user.email
json.posts @user.posts do |post|
  json.id post.id
  json.title post.title
end

最初はシンプルでいいんですが、以下のようなケースで破綻します。

  • 複数のエンドポイントで同じuser表現が必要になる → コピペ地獄
  • API バージョニングが必要になる → view ファイルが爆増
  • N+1が発生しても気づきにくい → includes忘れでパフォーマンス劣化

3-2. ActiveModelSerializerを導入したら逆に困った

一方で、「オブジェクト指向っぽいから」とAMSを導入すると、別の問題が出ます。

# app/serializers/user_serializer.rb
class UserSerializer < ActiveModel::Serializer
  attributes :id, :name, :email
  has_many :posts
end
# controller
render json: @user, serializer: UserSerializer

これ自体は綺麗なんですが、

  • 暗黙的な動作が多い(「has_many」がどんなSQLを発行するか見えない)
  • 条件分岐が複雑になると途端に辛い(あるユーザーには特定フィールドを出したくない、など)
  • メンテナンスが止まりがち(gemのissue見ると分かる)

私が参画したプロジェクトでは、AMSで複雑な権限制御をしようとして、結局Serializerクラスが500行を超える魔境になってました。

3-3. パフォーマンスの罠

どちらを使っても共通して起きるのが N+1問題 です。

# Jbuilderの例
json.users @users do |user|
  json.id user.id
  json.latest_post_title user.posts.order(created_at: :desc).first&.title
end

これ、「@users」が100件あったら、「user.posts」のクエリが100回走ります。

4. After:基本的な解決パターン

4-1. 使い分けの判断基準

実務では、以下のマトリクスで判断するのが確実です。

シンプルなAPI、バージョニング不要
 推奨: Jbuilder
 理由: Railsの標準、学習コストが低い

複数エンドポイントで共通の表現
 推奨: AMS(または自作PORO)
 理由: 再利用性が高い

複雑な条件分岐・権限制御
 推奨: 自作PORO
 理由: 明示的に書ける

GraphQL的な柔軟性が必要
 推奨: 自作PORO + パラメータ
 理由: AMSの暗黙制御を避ける

私の実務での結論:

  • 小〜中規模API → Jbuilder + partial活用
  • 複雑な権限制御あり → 自作PORベースのSerializerクラス
  • AMSは「レガシーコードで既に使われている」場合のみ継続

4-2. Jbuilderのベストプラクティス

Partialで再利用する

# app/views/api/users/_user.json.jbuilder
json.id user.id
json.name user.name
json.email user.email
# app/views/api/users/index.json.jbuilder
json.users @users do |user|
  json.partial! 'api/users/user', user: user
end

N+1を防ぐ

# controller
@users = User.includes(:posts).all
# view
json.users @users do |user|
  json.partial! 'api/users/user', user: user
  json.posts user.posts do |post|
    json.partial! 'api/posts/post', post: post
  end
end

4-3. ActiveModelSerializerを使う場合の注意点

明示的にincludesを指定

class UserSerializer < ActiveModel::Serializer
  attributes :id, :name, :email
  has_many :posts
 
  # これを忘れるとN+1
end
# controller
@users = User.includes(:posts).all
render json: @users, each_serializer: UserSerializer

条件分岐は 「if」 オプションで

class UserSerializer < ActiveModel::Serializer
  attributes :id, :name, :email, :phone
 
  attribute :phone, if: -> { scope&.admin? }
 
  def phone
    object.phone_number
  end
end
1
0
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?