1
1

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初心者が完全理解すべきMVCアーキテクチャ - 図解で学ぶデータの流れ

Last updated at Posted at 2025-11-09

はじめに

前回の記事では、Web技術の歴史とRackの正体について学びました。

今回は、Rails内部のMVCアーキテクチャについて、データがどのように流れるのかを徹底的に解説します。

「なんとなく動いている」状態から「完全に理解している」状態へステップアップしましょう!

対象読者

  • Railsを使い始めたばかりの方
  • Model、View、Controllerの役割が曖昧な方
  • クライアントからレスポンスまでの完全な流れを知りたい方

MVCアーキテクチャとは

MVCは、アプリケーションを3つの役割に分ける設計パターンです。

  • Model:データ管理
  • View:画面表示
  • Controller:処理の制御

なぜMVCで分けるのか?

分けない場合の問題:

# 全部一緒くた(カオス!)
def show_users
  # データベース接続
  conn = Database.connect
  # SQL実行
  users = conn.execute("SELECT * FROM users")
  # HTML生成
  html = "<h1>ユーザー一覧</h1>"
  users.each do |user|
    html += "<p>#{user['name']}</p>"
  end
  # レスポンス返却
  return html
end

問題点:

  • 変更が大変(HTMLを変えるだけでもSQL周辺のコードを触る)
  • テストしにくい
  • チームで分業できない

MVCで分けた場合:

# Controller(司令塔)
def index
  @users = User.all  # Modelに依頼
  # Viewに渡す
end

# Model(データ管理)
class User < ApplicationRecord
  # データベース操作
end

# View(画面表示)
# app/views/users/index.html.erb
<h1>ユーザー一覧</h1>
<% @users.each do |user| %>
  <p><%= user.name %></p>
<% end %>

メリット:

  • 役割が明確
  • 変更しやすい
  • テストしやすい
  • チームで分業できる

完全なデータフロー

クライアントからクライアントまでの旅

ユーザーがブラウザで「ユーザー一覧」ページを開くときの完全な流れを見ていきましょう。

クライアント(ブラウザ)
  ↓ HTTPリクエスト
Webサーバー(Nginx/Apache)
  ↓
Rackインターフェース
  ↓
【Railsの世界に入る】
  ↓
Controller(司令塔)
  ↓ データ取得依頼
Model(データ管理者)
  ↓ SQL実行
Database(MySQL/PostgreSQL)
  ↓ データ返却
Model
  ↓ データを返す
Controller
  ↓ データを渡してHTML生成依頼
View(デザイナー)
  ↓ 生成したHTMLを返す
Controller
  ↓
【Railsの世界から出る】
  ↓
Rackインターフェース
  ↓
Webサーバー
  ↓ HTTPレスポンス
クライアント(ブラウザに表示)

ポイント

  1. Controllerがハブ(中心) になっている
  2. 行きも帰りも同じ道を通る
  3. ViewもModelもControllerを経由する
  4. Controllerは常に処理の流れを制御している

MVCの各役割を詳しく解説

Controller(司令塔)

役割:

  • リクエストを最初に受け取る
  • 「何をすべきか」を判断
  • ModelとViewに指示を出す

具体例:

# app/controllers/users_controller.rb
class UsersController < ApplicationController
  # ユーザー一覧を表示
  def index
    @users = User.all  # Modelに「全ユーザー取得して」と依頼
    # 自動的にapp/views/users/index.html.erbを呼ぶ
  end
  
  # 特定のユーザーを表示
  def show
    @user = User.find(params[:id])  # IDで1人取得
  end
  
  # 新規ユーザー作成
  def create
    @user = User.new(user_params)
    if @user.save  # Modelに保存を依頼
      redirect_to @user  # 成功したらユーザーページへ
    else
      render :new  # 失敗したら入力画面に戻る
    end
  end
  
  private
  
  def user_params
    params.require(:user).permit(:name, :email)
  end
end

Controllerの責務:

  • ✅ リクエストパラメータの取得
  • ✅ Modelへのデータ操作依頼
  • ✅ Viewへのデータ受け渡し
  • ✅ リダイレクトやレンダリングの制御
  • ❌ SQL を直接書く(Modelの仕事)
  • ❌ HTMLを直接生成(Viewの仕事)

Model(データ管理者)

役割:

  • データベースとのやり取り
  • ビジネスロジックの実装
  • データの検証(バリデーション)

具体例:

# app/models/user.rb
class User < ApplicationRecord
  # バリデーション
  validates :name, presence: true
  validates :email, presence: true, uniqueness: true
  
  # 関連付け
  has_many :posts
  has_many :comments
  
  # ビジネスロジック
  def full_name
    "#{first_name} #{last_name}"
  end
  
  # スコープ(よく使う検索条件)
  scope :active, -> { where(active: true) }
  scope :recent, -> { order(created_at: :desc) }
end

よく使うModelの操作:

# 全件取得
User.all

# 条件検索
User.where(age: 20)
User.where("age > ?", 20)

# 1件取得
User.find(1)  # IDで検索
User.find_by(email: "test@example.com")  # 条件で検索

# 新規作成
user = User.new(name: "太郎", email: "taro@example.com")
user.save

# または
User.create(name: "太郎", email: "taro@example.com")

# 更新
user = User.find(1)
user.update(name: "新しい名前")

# 削除
user = User.find(1)
user.destroy

Modelの責務:

  • ✅ データベース操作
  • ✅ データの検証
  • ✅ ビジネスロジック
  • ✅ 関連付け(has_many等)
  • ❌ HTTPリクエストの処理(Controllerの仕事)
  • ❌ HTMLの生成(Viewの仕事)

View(デザイナー)

役割:

  • HTMLの生成
  • ユーザーに見せる画面を作る
  • Controllerから渡されたデータを表示

具体例:

<!-- app/views/users/index.html.erb -->
<h1>ユーザー一覧</h1>

<table>
  <thead>
    <tr>
      <th>ID</th>
      <th>名前</th>
      <th>メール</th>
      <th>操作</th>
    </tr>
  </thead>
  <tbody>
    <% @users.each do |user| %>
      <tr>
        <td><%= user.id %></td>
        <td><%= user.name %></td>
        <td><%= user.email %></td>
        <td>
          <%= link_to '詳細', user_path(user) %>
          <%= link_to '編集', edit_user_path(user) %>
          <%= link_to '削除', user_path(user), method: :delete, 
                      data: { confirm: '本当に削除しますか?' } %>
        </td>
      </tr>
    <% end %>
  </tbody>
</table>

<%= link_to '新規作成', new_user_path, class: 'btn btn-primary' %>

ERBの書き方:

<%# コメント(画面に表示されない) %>

<% # Rubyコードを実行(画面に表示しない) %>
<% @users.each do |user| %>
  ...
<% end %>

<%= # Rubyコードを実行して結果を表示 %>
<%= user.name %>

<%== # HTMLエスケープせずに表示(XSS注意!) %>
<%== user.bio %>

Viewの責務:

  • ✅ HTMLの生成
  • ✅ データの表示
  • ✅ フォームの作成
  • ✅ リンクの生成
  • ❌ データベース操作(Modelの仕事)
  • ❌ 複雑なロジック(Controllerの仕事)

実例で理解する:ユーザー一覧の表示

ステップ1:ルーティング設定

# config/routes.rb
Rails.application.routes.draw do
  resources :users  # RESTfulなルートを自動生成
end

これで以下のルートが自動生成されます:

HTTPメソッド パス Controller#Action 用途
GET /users users#index 一覧
GET /users/:id users#show 詳細
GET /users/new users#new 新規作成画面
POST /users users#create 作成実行
GET /users/:id/edit users#edit 編集画面
PATCH/PUT /users/:id users#update 更新実行
DELETE /users/:id users#destroy 削除

ステップ2:Controllerで処理

# app/controllers/users_controller.rb
class UsersController < ApplicationController
  def index
    # Step 1: Modelに全ユーザー取得を依頼
    @users = User.all
    
    # Step 2: 自動的にapp/views/users/index.html.erbが呼ばれる
  end
end

ステップ3:Modelがデータ取得

# app/models/user.rb
class User < ApplicationRecord
  # User.allが呼ばれると、ActiveRecordが自動的にSQLを生成
  # SELECT * FROM users;
end

ステップ4:Viewで表示

<!-- app/views/users/index.html.erb -->
<h1>ユーザー一覧</h1>
<% @users.each do |user| %>
  <div class="user-card">
    <h2><%= user.name %></h2>
    <p><%= user.email %></p>
  </div>
<% end %>

完全な流れの再確認

1. ブラウザ:http://localhost:3000/users にアクセス
   ↓
2. ルーティング:「GET /users は UsersController#index だな」
   ↓
3. Controller:「User.allでデータ取得しよう」
   ↓
4. Model:「SELECT * FROM users; を実行」
   ↓
5. Database:データを返す
   ↓
6. Model:Rubyオブジェクトに変換してControllerに返す
   ↓
7. Controller:「@users = [データ] をViewに渡す」
   ↓
8. View:「@usersを使ってHTMLを生成」
   ↓
9. Controller:生成されたHTMLを受け取る
   ↓
10. Rack → Webサーバー → ブラウザへレスポンス

インスタンス変数(@users)の役割

Controllerから Viewへデータを渡すときに使うのがインスタンス変数です。

# Controller
def index
  @users = User.all  # @をつける
end
<!-- View -->
<% @users.each do |user| %>  <!-- @usersにアクセスできる -->
  <%= user.name %>
<% end %>

なぜ@をつけるのか?

  • Controllerのインスタンス変数がViewで自動的に使える仕組み
  • Railsの「魔法」の一つ

ローカル変数だとどうなる?

# Controller
def index
  users = User.all  # @なし
end
<!-- View -->
<% users.each do |user| %>  <!-- エラー!usersが見つからない -->
  <%= user.name %>
<% end %>

よくある質問

Q1: ViewからModelに直接アクセスできる?

技術的には可能ですが、やるべきではありません

<!-- 悪い例 -->
<% User.all.each do |user| %>  <!-- ViewがModelを直接呼んでいる -->
  <%= user.name %>
<% end %>

問題点:

  • Viewに処理が漏れる
  • テストしにくい
  • 複雑なクエリをViewに書くことになる

正しい方法:

# Controller
def index
  @users = User.all
end
<!-- View -->
<% @users.each do |user| %>
  <%= user.name %>
<% end %>

Q2: ControllerでHTMLを生成できる?

技術的には可能ですが、やるべきではありません

# 悪い例
def index
  @users = User.all
  html = "<h1>ユーザー一覧</h1>"
  @users.each do |user|
    html += "<p>#{user.name}</p>"
  end
  render html: html.html_safe
end

問題点:

  • Controllerが肥大化
  • HTMLの変更が困難
  • デザイナーが作業できない

正しい方法:
ControllerはViewに任せる。

Q3: 複雑な処理はどこに書く?

シンプルな判断基準:

処理内容 場所
データベース操作 Model
リクエスト処理、フロー制御 Controller
HTML生成、表示ロジック View
複雑なビジネスロジック Model(またはService Object)
複雑な表示ロジック Helper(または View Object)

まとめ

MVCの3つの役割

  1. Controller(司令塔)

    • リクエストを受け取る
    • ModelとViewに指示を出す
    • 処理の流れを制御
  2. Model(データ管理者)

    • データベース操作
    • ビジネスロジック
    • データの検証
  3. View(デザイナー)

    • HTMLの生成
    • データの表示
    • ユーザーインターフェース

データの流れ(完全版)

クライアント
  ↓
Webサーバー
  ↓
Rackインターフェース
  ↓
Controller
  ↓
Model
  ↓
Controller
  ↓
View
  ↓
Controller
  ↓
Rackインターフェース
  ↓
Webサーバー
  ↓
クライアント

重要ポイント:

  • Controllerが常にハブになる
  • 行きも帰りも同じ道を通る
  • 各層が明確に役割分担している

なぜMVCを理解すべきか

  • エラーが出たときに「どこで起きているか」が分かる
  • コードをどこに書くべきか迷わなくなる
  • Railsの規約に沿った開発ができる
  • チームで開発しやすくなる

次のステップ

次の記事では、HTTPリクエスト/レスポンスの実際の中身ActiveRecordの詳細を学びます!

参考資料


この記事が役に立ったら、ぜひいいねストックをお願いします!
質問やフィードバックもお気軽にコメントください 😊

1
1
1

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
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?