0
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?

HTTPリクエスト/レスポンスとActiveRecordを理解する - Railsの内部で何が起きているのか

Last updated at Posted at 2025-11-17

はじめに

これまでの記事で、Web技術の歴史とMVCアーキテクチャについて学んできました。

  • 【記事1】Web技術の歴史とRackの正体を理解する
  • 【記事2】Rails初心者が完全理解すべきMVCアーキテクチャ

今回は最終回として、実際のHTTPリクエスト/レスポンスの中身ActiveRecordの仕組みを徹底解説します。

これで「Railsで何が起きているのか」が完全に理解できます!

対象読者

  • HTTPリクエスト/レスポンスの中身を知りたい方
  • ActiveRecordが何をしているのか理解したい方
  • ERBテンプレートの仕組みを知りたい方
  • ブラウザとサーバーのやり取りを完全に理解したい方

HTTPリクエストとは

HTTP(HyperText Transfer Protocol)は、ブラウザとサーバーが通信するためのプロトコル(約束事です。

リクエストの構成要素

HTTPリクエストは以下の要素で構成されています:

  1. HTTPメソッド:何をしたいか(GET、POST等)
  2. パス:どのページか(/users、/posts/1等)
  3. ヘッダー:追加情報(Cookie、認証等)
  4. ボディ:送信データ(POSTの場合)

実例1:ユーザー一覧を表示する

シナリオ

ブラウザのアドレスバーに https://example.com/users と入力してEnter

HTTPリクエスト

GET /users HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Chrome/120.0.0.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: ja,en-US;q=0.9,en;q=0.8
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Cookie: _session_id=abc123xyz; user_id=42

リクエストの解説

要素 意味
HTTPメソッド GET データを取得したい(見るだけ)
パス /users ユーザー一覧ページ
Host example.com アクセス先のドメイン
User-Agent Mozilla/5.0... ブラウザの種類とバージョン
Accept text/html... HTMLを受け取りたい
Cookie _session_id=... ログイン状態などを保持

サーバー内部の処理

1. Webサーバー(Nginx)がリクエスト受信
   ↓
2. Rack「GETリクエスト、/usersへのアクセスだな」
   ↓
3. Railsルーティング
   GET /users → UsersController#index
   ↓
4. UsersController#index実行
# app/controllers/users_controller.rb
class UsersController < ApplicationController
  def index
    # Step 1: Modelに全ユーザー取得を依頼
    @users = User.all
    
    # Step 2: 自動的にViewが呼ばれる
  end
end
# app/models/user.rb
class User < ApplicationRecord
  # User.all が呼ばれると...
end

ActiveRecordが内部で実行するSQL:

SELECT `users`.* FROM `users`

取得結果(Rubyオブジェクトに変換):

[
  #<User id: 1, name: "田中太郎", email: "tanaka@example.com">,
  #<User id: 2, name: "佐藤花子", email: "sato@example.com">,
  #<User id: 3, name: "鈴木一郎", email: "suzuki@example.com">
]

Viewでの処理

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

<ul>
  <% @users.each do |user| %>
    <li>
      <strong><%= user.name %></strong>
      (<%= user.email %>)
    </li>
  <% end %>
</ul>

ERBの処理:

  1. <% @users.each do |user| %> → ループ開始(画面に表示しない)
  2. <%= user.name %> → 値を取得して表示
  3. 最終的にHTMLを生成

生成されるHTML:

<h1>ユーザー一覧</h1>

<ul>
  <li>
    <strong>田中太郎</strong>
    (tanaka@example.com)
  </li>
  <li>
    <strong>佐藤花子</strong>
    (sato@example.com)
  </li>
  <li>
    <strong>鈴木一郎</strong>
    (suzuki@example.com)
  </li>
</ul>

HTTPレスポンス

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 1234
Set-Cookie: _session_id=abc123xyz; path=/; HttpOnly
X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
Cache-Control: no-cache

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>ユーザー一覧</title>
</head>
<body>
  <h1>ユーザー一覧</h1>
  <ul>
    <li>
      <strong>田中太郎</strong>
      (tanaka@example.com)
    </li>
    <li>
      <strong>佐藤花子</strong>
      (sato@example.com)
    </li>
    <li>
      <strong>鈴木一郎</strong>
      (suzuki@example.com)
    </li>
  </ul>
</body>
</html>

レスポンスの解説

要素 意味
ステータスコード 200 OK 成功!
Content-Type text/html; charset=utf-8 HTMLを返す、文字コードはUTF-8
Content-Length 1234 データサイズ(バイト)
Set-Cookie _session_id=... セッション情報を保存
X-Frame-Options SAMEORIGIN セキュリティ設定
Body <!DOCTYPE html>... 実際のHTMLデータ

ブラウザでの処理

  1. HTTPレスポンスを受信
  2. Content-Type: text/html → 「HTMLだな」と認識
  3. HTMLをパース(解析)
  4. 画面に表示

実例2:新規ユーザー登録

シナリオ

ユーザー登録フォームに入力して「登録」ボタンをクリック

新規登録フォーム(GET)

まず、フォームを表示するためのリクエスト:

GET /users/new HTTP/1.1
Host: example.com

Controller:

def new
  @user = User.new  # 空のUserオブジェクト
end

View:

<!-- app/views/users/new.html.erb -->
<h1>新規ユーザー登録</h1>

<%= form_with model: @user, url: users_path do |f| %>
  <div>
    <%= f.label :name, "名前" %>
    <%= f.text_field :name %>
  </div>
  
  <div>
    <%= f.label :email, "メールアドレス" %>
    <%= f.email_field :email %>
  </div>
  
  <div>
    <%= f.label :password, "パスワード" %>
    <%= f.password_field :password %>
  </div>
  
  <%= f.submit "登録" %>
<% end %>

生成されるHTML:

<h1>新規ユーザー登録</h1>

<form action="/users" method="post">
  <input type="hidden" name="authenticity_token" value="...">
  
  <div>
    <label for="user_name">名前</label>
    <input type="text" name="user[name]" id="user_name">
  </div>
  
  <div>
    <label for="user_email">メールアドレス</label>
    <input type="email" name="user[email]" id="user_email">
  </div>
  
  <div>
    <label for="user_password">パスワード</label>
    <input type="password" name="user[password]" id="user_password">
  </div>
  
  <input type="submit" value="登録">
</form>

フォーム送信(POST)

ユーザーが「登録」ボタンをクリック:

POST /users HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 156

authenticity_token=xyz789&user[name]=山田太郎&user[email]=yamada@example.com&user[password]=secret123

リクエストの解説

要素 意味
HTTPメソッド POST データを作成する
パス /users ユーザーを作成
Content-Type application/x-www-form-urlencoded フォームデータ
Body user[name]=山田太郎&... 送信データ

サーバー内部の処理

Railsのルーティング:

POST /users → UsersController#create

Controller:

class UsersController < ApplicationController
  def create
    # Step 1: パラメータからUserオブジェクトを作成
    @user = User.new(user_params)
    
    # Step 2: データベースに保存
    if @user.save
      # 成功:ユーザー詳細ページへリダイレクト
      redirect_to @user, notice: "ユーザーを登録しました"
    else
      # 失敗:再度入力画面を表示
      render :new, status: :unprocessable_entity
    end
  end
  
  private
  
  def user_params
    # Strong Parameters:許可されたパラメータのみ受け取る
    params.require(:user).permit(:name, :email, :password)
  end
end

Modelでの処理:

class User < ApplicationRecord
  # バリデーション
  validates :name, presence: true
  validates :email, presence: true, uniqueness: true
  validates :password, presence: true, length: { minimum: 6 }
  
  # パスワードの暗号化
  has_secure_password
end

ActiveRecordが実行するSQL(成功時):

BEGIN
INSERT INTO `users` (`name`, `email`, `password_digest`, `created_at`, `updated_at`)
VALUES ('山田太郎', 'yamada@example.com', '$2a$12$...', '2024-01-15 10:30:00', '2024-01-15 10:30:00')
COMMIT

HTTPレスポンス(成功時)

HTTP/1.1 302 Found
Location: /users/4
Set-Cookie: _session_id=new_session_id; path=/; HttpOnly
Content-Type: text/html; charset=utf-8

<html><body>You are being <a href="/users/4">redirected</a>.</body></html>

レスポンスの解説

要素 意味
ステータスコード 302 Found リダイレクト(別ページへ移動)
Location /users/4 この新しいユーザーのページへ
Set-Cookie 新しいセッションID セッション更新

ブラウザの処理

  1. 302 Found を受信
  2. Location: /users/4 を見る
  3. 自動的に /users/4 へGETリクエストを送る
  4. ユーザー詳細ページが表示される

HTTPメソッドの使い分け

RESTful設計

RailsはREST(Representational State Transfer)という設計思想に従っています。

HTTPメソッド 意味 用途
GET 取得(読み取り) ページ表示、データ取得 ユーザー一覧、詳細表示
POST 作成 新規データ作成 ユーザー登録
PATCH/PUT 更新 既存データ更新 プロフィール編集
DELETE 削除 データ削除 アカウント削除

Railsでの対応

# config/routes.rb
resources :users

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

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

HTTPステータスコード

サーバーは処理結果をステータスコードで返します。

主要なステータスコード

コード 意味 説明
200 OK 成功 ページ正常表示
201 Created 作成成功 ユーザー登録成功
204 No Content 成功(返すデータなし) 削除成功
301 Moved Permanently 恒久的リダイレクト ドメイン変更
302 Found 一時的リダイレクト ログイン後の遷移
400 Bad Request 不正なリクエスト パラメータエラー
401 Unauthorized 認証が必要 ログインが必要
403 Forbidden アクセス権限なし 管理者のみ
404 Not Found ページが存在しない 存在しないURL
422 Unprocessable Entity バリデーションエラー 入力エラー
500 Internal Server Error サーバーエラー バグ、例外
503 Service Unavailable サービス利用不可 メンテナンス中

Railsでの使い方

# 成功(200 OK)
def show
  @user = User.find(params[:id])
  # デフォルトで200が返る
end

# リダイレクト(302 Found)
def create
  if @user.save
    redirect_to @user  # 302
  end
end

# バリデーションエラー(422 Unprocessable Entity)
def create
  if @user.save
    redirect_to @user
  else
    render :new, status: :unprocessable_entity  # 422
  end
end

# Not Found(404)
def show
  @user = User.find_by(id: params[:id])
  if @user.nil?
    render file: "#{Rails.root}/public/404.html", status: :not_found
  end
end

ActiveRecordの仕組み

ActiveRecordは、RailsのORM(Object-Relational Mapping)です。

ORMとは

ORMは、データベースのテーブルとRubyのオブジェクトを対応づける技術です。

データベース(SQL)     ⇔    Ruby(オブジェクト)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
usersテーブル          ⇔    Userクラス
1レコード(行)        ⇔    1つのUserオブジェクト
カラム(列)           ⇔    属性(name、email等)

ActiveRecordの魔法

SQL を書かなくてもデータベース操作ができます。

例1:全件取得

ActiveRecord:

users = User.all

実行されるSQL:

SELECT `users`.* FROM `users`

例2:条件検索

ActiveRecord:

adults = User.where("age >= ?", 20)

実行されるSQL:

SELECT `users`.* FROM `users` WHERE (age >= 20)

例3:新規作成

ActiveRecord:

user = User.create(name: "太郎", email: "taro@example.com")

実行されるSQL:

INSERT INTO `users` (`name`, `email`, `created_at`, `updated_at`)
VALUES ('太郎', 'taro@example.com', '2024-01-15 10:00:00', '2024-01-15 10:00:00')

例4:更新

ActiveRecord:

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

実行されるSQL:

UPDATE `users` SET `name` = '新しい名前', `updated_at` = '2024-01-15 10:05:00'
WHERE `users`.`id` = 1

例5:削除

ActiveRecord:

user = User.find(1)
user.destroy

実行されるSQL:

DELETE FROM `users` WHERE `users`.`id` = 1

ActiveRecordの主要メソッド

検索系

# 全件取得
User.all

# 1件取得(IDで)
User.find(1)

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

# 複数件取得(条件で)
User.where(age: 20)
User.where("age > ?", 20)

# 並び替え
User.order(created_at: :desc)
User.order("name ASC")

# 件数制限
User.limit(10)

# 組み合わせ
User.where("age > ?", 20).order(created_at: :desc).limit(10)

作成系

# 方法1:new + save
user = User.new(name: "太郎", email: "taro@example.com")
user.save

# 方法2:create(newとsaveを同時に)
User.create(name: "太郎", email: "taro@example.com")

# 方法3:create!(失敗時に例外)
User.create!(name: "太郎", email: "taro@example.com")

更新系

user = User.find(1)

# 方法1:属性変更 + save
user.name = "新しい名前"
user.save

# 方法2:update
user.update(name: "新しい名前")

# 方法3:update!(失敗時に例外)
user.update!(name: "新しい名前")

削除系

user = User.find(1)

# 削除
user.destroy

# または
User.destroy(1)

# 複数削除
User.where("age < ?", 18).destroy_all

バリデーション

ActiveRecordは、データベースに保存する前にバリデーション(検証)を行います。

class User < ApplicationRecord
  # 存在チェック
  validates :name, presence: true
  
  # 一意性チェック
  validates :email, uniqueness: true
  
  # 長さチェック
  validates :password, length: { minimum: 6 }
  
  # 形式チェック
  validates :email, format: { with: /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i }
  
  # カスタムバリデーション
  validate :custom_validation
  
  private
  
  def custom_validation
    if name == "admin"
      errors.add(:name, "adminは使用できません")
    end
  end
end

使い方:

user = User.new(name: "", email: "invalid")

if user.save
  # 保存成功
else
  # 保存失敗
  puts user.errors.full_messages
  # => ["Name can't be blank", "Email is invalid"]
end

# valid? で事前チェック
user.valid?  # => false
user.errors.full_messages  # エラーメッセージの配列

ERBテンプレートの仕組み

ERB(Embedded Ruby)は、HTMLにRubyコードを埋め込むテンプレートエンジンです。

ERBの基本文法

<%# これはコメント(表示されない) %>

<% # Rubyコードを実行(画面に表示しない) %>
<% if @user.admin? %>
  <p>管理者です</p>
<% end %>

<%= # Rubyコードを実行して結果を表示 %>
<p>こんにちは、<%= @user.name %>さん</p>

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

データの埋め込み

Controller:

def index
  @users = User.all
end

View:

<h1>ユーザー一覧(全<%= @users.count %>名)</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><%= user.created_at.strftime("%Y年%m月%d日") %></td>
      </tr>
    <% end %>
  </tbody>
</table>

条件分岐

<% if @user.admin? %>
  <p>管理者メニュー</p>
  <%= link_to "ユーザー管理", admin_users_path %>
<% elsif @user.premium? %>
  <p>プレミアム会員</p>
  <%= link_to "特典ページ", premium_path %>
<% else %>
  <p>一般会員</p>
  <%= link_to "アップグレード", upgrade_path %>
<% end %>

ループ処理

<!-- each -->
<% @posts.each do |post| %>
  <article>
    <h2><%= post.title %></h2>
    <p><%= post.body %></p>
  </article>
<% end %>

<!-- each_with_index -->
<% @items.each_with_index do |item, index| %>
  <p><%= index + 1 %>. <%= item.name %></p>
<% end %>

<!-- times -->
<% 5.times do |i| %>
  <p>繰り返し <%= i + 1 %></p>
<% end %>

パーシャル(部分テンプレート)

共通部分を切り出して再利用できます。

_user.html.erb:

<div class="user-card">
  <h3><%= user.name %></h3>
  <p><%= user.email %></p>
</div>

index.html.erb:

<h1>ユーザー一覧</h1>

<% @users.each do |user| %>
  <%= render 'user', user: user %>
<% end %>

<!-- または短縮記法 -->
<%= render @users %>

ブラウザの開発者ツールで確認

実際のHTTPリクエスト/レスポンスは、ブラウザの開発者ツールで確認できます。

確認方法

  1. 開発者ツールを開く

    • Chrome/Edge:F12 または Ctrl+Shift+I(Mac: Cmd+Option+I)
    • Firefox:F12
    • Safari:Cmd+Option+I
  2. Networkタブを選択

  3. ページをリロード

  4. リクエストをクリックして詳細を見る

    • Headers:リクエスト/レスポンスのヘッダー
    • Preview:レスポンスのプレビュー
    • Response:レスポンスの生データ
    • Timing:処理時間

確認できる情報

  • HTTPメソッド(GET、POST等)
  • ステータスコード(200、404等)
  • リクエストヘッダー
  • レスポンスヘッダー
  • Cookie
  • レスポンスボディ(HTML、JSON等)
  • 処理時間

まとめ

HTTPリクエスト/レスポンスの流れ

1. クライアント:HTTPリクエスト送信
   ├─ HTTPメソッド(GET、POST等)
   ├─ パス(/users等)
   ├─ ヘッダー(Cookie等)
   └─ ボディ(POSTデータ)
   ↓
2. サーバー:リクエスト処理
   ├─ ルーティング
   ├─ Controller実行
   ├─ Model(ActiveRecord)でDB操作
   └─ View(ERB)でHTML生成
   ↓
3. サーバー:HTTPレスポンス返却
   ├─ ステータスコード(200、302等)
   ├─ ヘッダー(Content-Type等)
   └─ ボディ(HTML、JSON等)
   ↓
4. クライアント:レスポンス受信・表示

ActiveRecordの役割

  • SQLを書かずにデータベース操作
  • Rubyのオブジェクトとして扱える
  • バリデーション機能
  • 関連付け(has_many等)

ERBテンプレートの役割

  • HTMLにRubyコードを埋め込む
  • Controllerから渡されたデータを表示
  • 条件分岐やループ処理
  • 最終的にHTMLを生成

重要ポイント

  1. HTTPはリクエスト/レスポンスの往復
  2. HTTPメソッドで「何をするか」を表現
  3. ステータスコードで「結果」を表現
  4. ActiveRecordはSQLを自動生成
  5. ERBはHTMLテンプレートにデータを埋め込む
  6. Content-Typeでデータ形式を指定

シリーズ完結!

お疲れ様でした!これで3部作が完結です。

  • 【記事1】Web技術の歴史とRackの正体を理解する
  • 【記事2】Rails初心者が完全理解すべきMVCアーキテクチャ
  • 【記事3】HTTPリクエスト/レスポンスとActiveRecordを理解する

この3つの記事で、Railsの全体像が完全に理解できたはずです!

次のステップ

さらに学びたい方へ:

  • API開発:JSON形式でデータを返す
  • 認証/認可:Devise、Pundit
  • テスト:RSpec、Minitest
  • 非同期処理:Sidekiq、Active Job
  • フロントエンド:Hotwire、React、Vue

参考資料


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

最後まで読んでいただき、ありがとうございました!

0
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
0
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?