カテゴリ: Rails 更新日: 2025/11/27

Railsのコントローラ肥大化を防ぐ方法!初心者でもわかるサービスオブジェクトとフォームオブジェクトの基本

コントローラの肥大化を防ぐ:サービスオブジェクト/フォームオブジェクト分離
コントローラの肥大化を防ぐ:サービスオブジェクト/フォームオブジェクト分離

先生と生徒の会話形式で理解しよう

生徒

「Railsでアプリを作ってたら、コントローラがどんどん長くなってきたんですけど、これって大丈夫なんですか?」

先生

「いいところに気づきましたね。コントローラが長くなると、修正や再利用が難しくなるので、分けた方がいいですね。」

生徒

「どうやって分けたらいいんですか?」

先生

「そこで登場するのが、サービスオブジェクトフォームオブジェクトです。それぞれ、役割を分担して、スッキリしたコードにできるんですよ。」

1. コントローラが肥大化する原因とは?

1. コントローラが肥大化する原因とは?
1. コントローラが肥大化する原因とは?

Ruby on Railsでは、コントローラがWebアプリケーションのリクエストを受け取り、適切な処理を行います。しかし、処理が増えてくると、1つのコントローラに多くの役割が集まりすぎてしまうことがあります。これをコントローラの肥大化と呼びます。

たとえば、「データの登録」「メール送信」「通知の作成」などをすべてコントローラに書いてしまうと、見通しが悪くなり、あとから修正したりテストしたりするのが大変になります。

2. コントローラの責務を分ける考え方

2. コントローラの責務を分ける考え方
2. コントローラの責務を分ける考え方

「責務(せきむ)」とは、「その場所が担当する役割」のことです。コントローラの本来の役割は、「ユーザーからのリクエストを受け取り、モデルやビューに橋渡しをする」ことです。

ビジネスロジック(例えば「ポイントを計算する」「外部サービスに通知する」など)は、本来モデルや別のクラスが担当すべきです。そこで登場するのがサービスオブジェクトフォームオブジェクトです。

3. サービスオブジェクトとは?

3. サービスオブジェクトとは?
3. サービスオブジェクトとは?

サービスオブジェクトは、「何か1つの処理をまとめるクラス」です。たとえば、「注文を作る」という処理があれば、それをクラスにまとめておき、コントローラから呼び出す形にします。

コントローラをシンプルに保ちつつ、処理の内容は別のファイルにまとめることで、コードが見やすくなります。


# app/services/order_creator.rb
class OrderCreator
  def initialize(user, product)
    @user = user
    @product = product
  end

  def call
    order = Order.create(user: @user, product: @product)
    Notification.send_order_created(order)
    order
  end
end

# orders_controller.rb
def create
  order = OrderCreator.new(current_user, product).call
  render json: { order_id: order.id }
end

4. フォームオブジェクトとは?

4. フォームオブジェクトとは?
4. フォームオブジェクトとは?

フォームオブジェクトは、「複数のモデルにまたがる入力フォーム」をまとめて扱うための仕組みです。

たとえば、ユーザー情報と住所情報を同時に入力させる場合、通常ならUserモデルとAddressモデルの両方に処理を書く必要があります。フォームオブジェクトを使えば、それをひとつのクラスにまとめられます。


# app/forms/user_registration_form.rb
class UserRegistrationForm
  include ActiveModel::Model

  attr_accessor :name, :email, :zip, :prefecture

  validates :name, :email, :zip, presence: true

  def save
    return false unless valid?

    user = User.create(name: name, email: email)
    Address.create(user: user, zip: zip, prefecture: prefecture)
  end
end

# users_controller.rb
def create
  form = UserRegistrationForm.new(user_params)
  if form.save
    redirect_to root_path
  else
    render :new
  end
end

5. どんなときに分離を検討すべきか

5. どんなときに分離を検討すべきか
5. どんなときに分離を検討すべきか

以下のような場合は、コントローラから処理を分離することをおすすめします。

  • 同じような処理を複数のコントローラで使いたいとき
  • 複雑なビジネスロジック(計算や外部API連携など)があるとき
  • フォームで複数のモデルを同時に扱うとき

最初は少し難しく感じるかもしれませんが、コードをキレイに保つための大事な考え方です。

6. サービスオブジェクトとフォームオブジェクトの違い

6. サービスオブジェクトとフォームオブジェクトの違い
6. サービスオブジェクトとフォームオブジェクトの違い

2つのオブジェクトは、それぞれ目的が違います。

  • サービスオブジェクト:特定の処理(注文・集計・通知など)をまとめる
  • フォームオブジェクト:入力フォームに関する処理(バリデーションや保存)をまとめる

どちらも、「1つのクラスに1つの責任だけを持たせる」という考え方を実現する手段です。

7. 具体的なファイル配置と命名ルール

7. 具体的なファイル配置と命名ルール
7. 具体的なファイル配置と命名ルール

サービスオブジェクトは、app/servicesディレクトリに配置します。名前は、「何をするか」が分かるように〇〇Service〇〇Creatorのようにするのが一般的です。

フォームオブジェクトは、app/formsに配置し、〇〇Form〇〇RegistrationFormといった名前をつけることが多いです。

こうしたルールに従うことで、他の人が見たときにも「このクラスは何のためにあるのか」が分かりやすくなります。

8. 小さく始めて少しずつ改善しよう

8. 小さく始めて少しずつ改善しよう
8. 小さく始めて少しずつ改善しよう

最初からすべてをサービスオブジェクトやフォームオブジェクトに分けようとしなくても大丈夫です。

まずは、「この処理はちょっと長いな」「テストしにくいな」と感じたところから、小さく切り出していくのがコツです。

慣れてくると、自然と「ここはサービスに分けよう」「このフォームは専用クラスを使おう」と判断できるようになります。

関連記事:
カテゴリの一覧へ
新着記事
New1
データベース
SQLの処理が遅くなる原因とは?初心者向けにデータベースパフォーマンス最適化を完全解説
New2
Ruby
RubyのネストHash操作を徹底解説!digとtransformメソッドで複雑なデータも楽々
New3
Rails
Railsインデックス設計の極意!爆速サイトを作るためのスキーマ設計ガイド
New4
データベース
SQLのCOMMITとROLLBACKとは?トランザクション操作を初心者向けに完全解説
人気記事
No.1
Java&Spring記事人気No1
Rails
Railsで日本語と時刻の設定をしよう!初心者でも安心のlocale/zone初期設定チートシート
No.2
Java&Spring記事人気No2
Ruby
PATHと環境変数の正しい設定!Windows・Mac・Linux別チェックリスト付き
No.3
Java&Spring記事人気No3
Ruby
Rubyのハッシュを徹底比較!シンボルキーと文字列キーの違いと使い分け
No.4
Java&Spring記事人気No4
Rails
Railsマイグレーションの型選びを完全ガイド!初心者が迷わないカラム設計
No.5
Java&Spring記事人気No5
Ruby
WindowsでRubyをインストールする方法!RubyInstallerとMSYS2を使った完全ガイド
No.6
Java&Spring記事人気No6
Rails
RailsモデルとActive Record基礎|ID戦略を完全理解!AUTO INCREMENT・UUID・ULIDの比較と導入手順
No.7
Java&Spring記事人気No7
データベース
ACID特性とは?データベーストランザクションの信頼性を初心者向けに徹底解説
No.8
Java&Spring記事人気No8
データベース
データベース正規化とは?初心者でもわかるデータ重複を防ぐSQL設計の基本