Skip to main content

第2章: Rails APIプロジェクト雛形

🎯 この章で学ぶこと(所要時間: 3時間)

この章では、Rails APIモードでプロジェクトを構築し、必要なGemの導入とテスト環境をセットアップします。また、実際の開発で必須となるGitブランチの使い方も学びます。

📢 はじめに

第1章ではDockerを使ってRailsが動く環境を構築しました。

第2章では本格的なAPIサーバーの土台を作っていきます。現代のWeb開発では、フロントエンドとバックエンドを分離することが一般的です。InstagramやTwitter、メルカリなど、みなさんが普段使っているアプリも、裏側ではAPIサーバーが動いています。

この章では、そんなモダンなWeb開発に必要な「Rails APIモード」を使って、プロジェクトの基盤を整えていきます。また、チーム開発で必須の「Gitブランチ」の使い方も実践的に学びます。

🎓 この章を終えると...

  • なぜAPIモードを使うのか、その理由が腹落ちする
  • Gitブランチを使った安全な開発フローが身につく
  • プロ仕様のGem選定ができるようになる
  • テスト駆動開発(TDD)の第一歩を踏み出せる
  • 実際の開発現場で使われている設定が理解できる

💡 この章で身につくスキル

  • 🌳 Gitブランチを使った機能開発フロー
  • 🚀 Rails APIモードの理解と構築
  • 💎 必要なGemの選定と設定
  • 🗄️ データベース接続の仕組み
  • 🌐 CORS(クロスオリジンリソース共有)の基礎
  • 🧪 RSpecによるテスト環境構築
  • 🔍 ブラウザでのAPI動作確認
📖 この章の進め方
  1. まずGitブランチについて学び、作業用ブランチを作成します
  2. Rails APIモードの概念を理解します
  3. 実際に手を動かしながら、順番に設定していきます
  4. 最後にGitHubにプッシュして、プルリクエストを作成します
📓 前提条件
  • 第1章でDockerコンテナが正常に動作していること
  • GitHubアカウントがあり、リポジトリをクローンしていること
  • ターミナルでコマンドが実行できること

それでは、プロの開発現場で使われている技術を、一つずつ身につけていきます。

📚 0. Gitブランチ入門

🌳 ブランチとは

開発を始める前に、Gitブランチについて理解します。ブランチは、メインの開発ラインから分岐して、独立して作業できる機能です。

💡 ブランチを使うメリット

想像してみてください。あなたが本を書いているとします:

  • mainブランチ = 出版される完成原稿
  • 作業ブランチ = 下書きや修正用のコピー

下書きで失敗しても、完成原稿には影響しません。

🔨 ブランチの作成

ここまでは概念の説明でした。実際に手を動かしていきます。

🚀 ここから実践開始

実際にGitブランチを作成して、第2章の作業を始めます。以下のコマンドを順番に実行していきます。

まず現在の状態を確認します:

ターミナルで実行
# 現在のブランチを確認
git branch
# => * main と表示される

# 現在の変更状況を確認
git status
# => nothing to commit と表示される

作業用ブランチを作成して切り替えます:

ターミナルで実行
# feature/chapter-2 というブランチを作成して切り替え
git checkout -b feature/chapter-2

# ブランチが切り替わったか確認
git branch
# => * feature/chapter-2 と表示される
💡 ブランチ名の付け方
  • feature/機能名: 新機能開発
  • fix/バグ名: バグ修正
  • refactor/対象: リファクタリング

これで準備完了です。以降の作業は全てこのブランチで行います。

1. Rails APIモードとは?

🤔 モダンなWebアプリケーション開発へ

Rails Tutorialでは、HTMLページを生成して返すWebアプリケーションを作りました。ユーザー登録、ログイン、マイクロポストの投稿など、全ての機能がHTMLとして返されていました。

最近のWebサービスでは、TwitterやInstagramのように、ブラウザだけでなくスマホアプリからも同じ投稿にアクセスできます。これはAPIサーバーという仕組みを使っているからです。

今回は、Rails Tutorialで学んだ知識を活かして、こうしたモダンなアプリケーションの作り方を学んでいきます。Ruby on Railsには、APIサーバーを効率的に作るためのRails APIモードという機能があるので、それを使っていきます。

📱 APIとは

**API(Application Programming Interface)**は、アプリケーション同士がデータをやり取りするための「窓口」です。

簡単に言うと:

  • フロントエンド(React、iOSアプリ、Androidアプリなど)が「データをください」とリクエスト
  • Rails APIが必要なデータをJSON形式で返す
  • フロントエンドがそのデータを使って画面を作る

📄 JSONとは

APIがデータを返すときによく使われる**JSON(JavaScript Object Notation)**について説明します。

📋 JSONは「データの共通言語」

JSON = 誰でも読めるデータ形式

Rails Tutorialでは:

  • ユーザー情報をHTMLで表示していました
  • <h1>Michael Hartl</h1><p>michael@example.com</p>のような形

APIサーバーでは、同じ情報をJSON形式で返します:

{
"user": {
"name": "Michael Hartl",
"email": "michael@example.com",
"created_at": "2024-01-05T10:00:00Z"
}
}

なぜJSONを使うの?

  • 📱 iPhoneアプリも読める
  • 💻 Reactアプリも読める
  • 🤖 Androidアプリも読める
  • 全員が同じデータを受け取って、それぞれの方法で表示する!

🔍 実際のAPIを体験してみよう!

ここで実際のAPIがどう動くか体験してみましょう。以下は郵便番号検索APIを呼び出す例です:

🏮 郵便番号検索APIデモ

実際のAPIを呼び出して、JSONデータがどのように返されるか見てみましょう!

💡 何が起きているの?

上のデモでは:

  1. **あなた(ブラウザ)**が郵便番号を入力
  2. 郵便番号検索APIにリクエストを送信
  3. APIがJSON形式で住所データを返す
  4. Reactがそのデータを受け取って画面に表示

これがまさにAPIの仕組みです!Rails APIモードで作るサーバーも、同じようにJSONデータを返します。

🤔 Rails TutorialとAPIモードの違い

Rails Tutorial方式(通常のRails):

Rails Tutorialのレスポンス例(HTML):

<html>
<body>
<h1>All users</h1>
<ul class="users">
<li>
<img src="/assets/gravatar.jpg" alt="Michael Hartl">
<a href="/users/1">Michael Hartl</a>
</li>
</ul>
</body>
</html>

Rails APIモードの動き

レスポンス例(JSON):

{
"todos": [
{
"id": 1,
"title": "買い物に行く",
"completed": false
},
{
"id": 2,
"title": "宿題をする",
"completed": true
}
]
}

🌍 1つのAPIを複数のアプリが使う仕組み

従来の方法(それぞれ別々に作る):

❌ 同じデータなのに3つも管理が必要...

APIモードを使った方法:

✅ 1つのデータベースを共有!

💡 メリット
  • データの一元管理 → 更新が1箇所で済む
  • 開発効率UP → APIを1つ作れば全アプリで使える
  • 一貫性の保証 → 全員が同じデータを見る

🌍 実際のサービスでの利用例

Rails APIモードが実際にどう使われているか見てみましょう:

📱 Instagram(Meta)の例

Instagramは1つのAPIで複数のプラットフォームに対応:

1つのRails API(実際にはPythonですが、仕組みは同じ)が、様々なクライアントにデータを提供:

  • 📱 iOSアプリ → Swift/SwiftUIで作られたネイティブアプリ
  • 🤖 Androidアプリ → Kotlin/Jetpack Composeで作られたネイティブアプリ
  • 💻 instagram.com → React.jsで作られたWebアプリ
  • Apple Watch → 通知機能だけの軽量版
  • 🖥️ デスクトップアプリ → Electronで作られたアプリ

全部違う見た目・操作感だけど、データの出どころは同じAPI!

他にも:

  • Twitter(X): 1つのAPIで Web/iOS/Android/TweetDeck に対応
  • メルカリ: 1つのAPIで Web/iOS/Android/メルペイ に対応
  • Netflix: 1つのAPIで Web/iOS/Android/TV/ゲーム機 に対応
💡 この方式のメリット
  1. 開発チームを分けられる

    • バックエンドチーム:Ruby/Railsのエキスパート
    • フロントエンドチーム:React/Vue/Swiftのエキスパート
  2. それぞれ得意な技術を使える

    • iOS開発者:Swift で最高のiPhoneアプリを作る
    • Web開発者:React で美しいWebサイトを作る
    • みんな同じAPIからデータを取得
  3. メンテナンスが楽

    • APIを1箇所修正すれば、全てのアプリに反映
    • 新機能の追加も1箇所でOK

📊 通常のRailsとAPIモードの違い

機能通常のRailsRails APIモードなぜ違う?
レスポンス形式HTML(Webページ)JSON(データのみ)フロントエンドが画面を作るから
セッション管理Cookieでユーザー情報保持トークンベース複数デバイス対応のため
CSRF対策自動で有効不要(トークンで認証)APIは別の認証方式を使うから
ミドルウェア多い(画面表示用)最小限速度重視!
💡 APIモードのメリット
  • 🚀 軽量・高速: 不要な機能を省いてパフォーマンス向上
  • 📱 マルチデバイス対応: Web、モバイル、デスクトップアプリから利用可能
  • 🔄 フロントエンド独立: React、Vue、Flutterなど何でも使える
  • 📈 スケーラブル: サーバーを増やしやすい設計

2. プロジェクトの構成確認

📁 現在のディレクトリ構成

前章で作成したDockerコンテナとRailsプロジェクトを使用します。まず環境が正しく動作しているか確認しましょう。

🚀 ここから実践開始!

前章で作成した環境が正しく動作しているか確認します。以下のコマンドを実行してください。

🔨 実際にやってみましょう! 環境の確認から始めます:

ターミナルで実行
# プロジェクトディレクトリに移動
cd todo-api

# Dockerコンテナが起動していることを確認
docker compose ps

期待される出力:

NAME                IMAGE               COMMAND                  SERVICE   CREATED       STATUS       PORTS
todo-api-db-1 mysql:8.0 "docker-entrypoint.s…" db 2 hours ago Up 2 hours 3306/tcp, 33060/tcp
todo-api-web-1 todo-api-web "entrypoint.sh bash …" web 2 hours ago Up 2 hours 0.0.0.0:3000->3000/tcp
💡 確認ポイント

STATUSカラムを確認してください:

  • Up 2 hoursrunning と表示されていれば、コンテナは正常に起動しています
  • 「Up」の後の時間(例:2 hours)は起動してからの経過時間を表します
  • もしExitedや何も表示されない場合は、docker compose up -d で起動します

🛠 プロジェクトの構成を理解しよう

📖 ここは読むだけでOK

プロジェクトの構成を確認しますが、まずは下記のコマンドを実行して、その後の説明を読んでください。

🔨 実際にやってみましょう! プロジェクトの構成を確認します:

ターミナルで実行
# プロジェクトのファイル構成を確認
ls -la

# Railsのバージョンを確認
docker compose exec web rails --version

生成されたファイル構造の重要な部分:

todo-api/
├── Dockerfile # Dockerイメージの設定
├── docker-compose.yml # Docker Compose設定
├── Gemfile # Rubyの依存関係管理
├── Gemfile.lock # 依存関係のバージョン固定
├── app/
│ ├── controllers/ # APIエンドポイントの処理
│ ├── models/ # データベースとの対話
│ └── ...
├── config/
│ ├── application.rb # アプリ全体の設定
│ ├── database.yml # DB接続設定
│ └── ...
└── ...
📝 APIモードで省略されるディレクトリ
  • app/views/: HTMLテンプレートは不要
  • app/assets/: CSS/JavaScriptも不要
  • app/helpers/: ビューヘルパーも不要

3. 必要なGemの追加

💎 Gemとは

Gemは、Rubyの世界での「パッケージ」や「ライブラリ」のことです。npmパッケージのRuby版だと思ってください。

💡 身近な例えで理解しよう

Gemは「料理の調味料」のようなもの:

  • 基本のRails = 塩・砂糖・醤油(基本調味料)
  • 追加Gem = オイスターソース、豆板醤(特殊調味料)

必要に応じて追加することで、より高機能なアプリが作れます。

🎯 今回追加するGemたち

ここまでGemの概念について説明しました。実際にGemを追加していきます。

🚀 ここから実践開始

Gemfileを編集して、必要なGemを追加します。以下の内容をそのままコピーして使ってください。

🔨 実際にやってみましょう! Gemfileを以下の内容で編集してください:

Gemfile
source "https://rubygems.org"

# Rubyバージョンの指定(3.4.0以上3.5.0未満を許可)
ruby "~> 3.4.0"

# ===== 基本のGem =====
gem "rails", "~> 8.0.2" # Railsフレームワーク本体
gem "mysql2", "~> 0.5" # MySQLデータベース接続用
gem "puma", ">= 5.0" # Webサーバー(高速・安定)

# ===== 認証・セキュリティ関連 =====
gem "bcrypt", "~> 3.1.7" # パスワードの暗号化(必須!)
gem "rack-cors" # 別ドメインからのアクセス許可

# ===== API開発用 =====
gem "active_model_serializers", "~> 0.10.0" # JSONレスポンスを綺麗に整形

# ===== 共通ユーティリティ =====
gem "tzinfo-data", platforms: %i[ windows jruby ] # タイムゾーン情報
gem "bootsnap", require: false # 起動高速化

# ===== 開発・テスト環境用 =====
group :development, :test do
gem "debug", platforms: %i[ mri windows ] # デバッグツール
gem "dotenv-rails" # 環境変数を.envファイルで管理
gem "rspec-rails", "~> 6.0" # テストフレームワーク(RSpec)
gem "factory_bot_rails" # テストデータ作成を簡単に
gem "faker" # ダミーデータ生成(テスト用)
end

# ===== 開発環境専用 =====
group :development do
gem "better_errors" # エラー画面を見やすく
gem "binding_of_caller" # エラー画面で変数の中身を確認
gem "rubocop", require: false # Rubyコードの書き方チェック
gem "rubocop-rails", require: false # Rails専用ルール
gem "rubocop-rspec", require: false # RSpec専用ルール
end

# ===== テスト環境専用 =====
group :test do
gem "shoulda-matchers", "~> 5.0" # テストを簡潔に書ける
gem "database_cleaner-active_record" # テスト後のDB掃除
gem "simplecov", require: false # テストカバレッジ測定
end

📦 Gemのインストール

🔨 実際にやってみましょう! 追加したGemをインストールします:

ターミナルで実行
# まず、Dockerコンテナ内でbundle installを実行してGemfile.lockを生成
docker compose run --rm web bundle install

# Gemfile.lockが生成されたら、Dockerイメージを再ビルド
docker compose build

# ビルドが完了したら、コンテナを再起動
docker compose up -d
💡 なぜこの手順が必要?
  1. docker compose run --rm web bundle install

    • Dockerコンテナ内でbundle installを実行
    • Gemfile.lockが生成/更新される
    • --rmオプションで実行後にコンテナを自動削除
  2. docker compose build

    • Gemfile.lockを含めてイメージを再ビルド
    • 次回からは高速に起動できる
  3. docker compose up -d

    • 新しいイメージでコンテナを起動

この方法により、ホストマシンにRubyがなくても、Docker内で完結できます!

💡 なぜコンテナ内の変更がホストに反映される?

第1章のボリュームマウントの説明を思い出してください:

volumes:
- .:/app # ホストの現在のディレクトリをコンテナの/appにマウント

このボリュームマウントにより:

  • ホスト → コンテナ: ホストのファイル変更が即座にコンテナに反映
  • コンテナ → ホスト: コンテナ内でのファイル作成・更新もホストに反映

つまり、docker compose run --rm web bundle installでコンテナ内に生成されたGemfile.lockは、自動的にホストマシン側にも作成されます!これがDockerボリュームの便利な点です。

💾 最初のコミット

Gemの追加は重要な変更なので、ここでコミットしておきましょう。

🔨 実際にやってみましょう! GemfileとGemfile.lockの変更をコミットします:

ターミナルで実行
# 変更内容を確認
git status
git diff Gemfile

# GemfileとGemfile.lockの変更をコミット
git add Gemfile Gemfile.lock
git commit -m "Gemfile更新"
💡 こまめなコミットの重要性
  • 変更を小さく分けることで、後から履歴を追いやすくなる
  • 問題が起きたときに、どの変更が原因か特定しやすい
  • チーム開発では、他のメンバーが理解しやすい

4. データベース設定

🗄️ データベース接続の仕組み

第1章で学んだDockerのネットワークについておさらいします。

📋 database.ymlの確認

前章で環境変数の設定は完了していますが、念のためconfig/database.ymlが正しく設定されているか確認しましょう。

📖 確認だけでOK

以下の内容になっているか確認するだけです。既に設定済みなので、編集は不要です。

📝 config/database.ymlが以下のようになっていることを確認してください:

config/database.yml
default: &default
adapter: mysql2 # MySQLを使用
encoding: utf8mb4 # 絵文字も保存できる文字コード
host: <%= ENV['DATABASE_HOST'] %> # 環境変数から読み込み
username: <%= ENV['DATABASE_USER'] %> # 環境変数から読み込み
password: <%= ENV['DATABASE_PASSWORD'] %> # 環境変数から読み込み
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> # 接続プール数

development:
<<: *default # defaultの設定を継承
database: todo_development # 開発用データベース名

test:
<<: *default
database: todo_test # テスト用データベース名

production:
<<: *default
database: todo_production # 本番用データベース名
💡 環境変数を使う理由
  • セキュリティ: パスワードをコードに直接書かない
  • 柔軟性: 環境ごとに異なる設定を簡単に切り替え
  • チーム開発: 各自の環境に合わせた設定が可能

5. CORS設定

🌐 CORSとは

**CORS(Cross-Origin Resource Sharing)**は、異なるドメイン間でのデータのやり取りを制御する仕組みです。

💡 身近な例えで理解しよう

CORSは「マンションのオートロック」のようなもの:

  • オートロックなし = 誰でも入れる(セキュリティリスク)
  • オートロックあり = 許可された人だけ入れる(安全)

RailsのAPIも、許可したフロントエンドからのアクセスだけを受け付けるようにします!

🔧 CORSの設定

CORSの概念を理解したところで、実際に設定していきましょう。

🚀 ここから実践開始!

Rails APIがフロントエンドからのアクセスを受け付けられるよう、CORSを設定します。

🔨 実際にやってみましょう! config/initializers/cors.rbを以下の内容で編集してください:

config/initializers/cors.rb
# CORSの設定ファイル
# このファイルを変更したらサーバーの再起動が必要です

Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
# 開発環境では指定したURLからのアクセスを許可
# 本番環境では、実際のフロントエンドのURLに変更する
origins ENV.fetch("FRONTEND_URL", "http://localhost:3001")

# 許可する内容の詳細設定
resource "*", # 全てのAPIパスで有効
headers: :any, # 全てのヘッダーを許可
methods: [:get, :post, :put, :patch, :delete, :options, :head], # 許可するHTTPメソッド
expose: ["Authorization"], # フロントエンドに公開するヘッダー
max_age: 600 # プリフライトリクエストのキャッシュ時間(秒)
end
end
⚠️ 本番環境での注意

本番環境では、origins*(全てのドメイン)を指定するのは危険です! 必ず特定のドメインのみを許可してください。

💾 CORS設定をコミット

CORS設定が完了したので、コミットしておきましょう。

🔨 実際にやってみましょう! CORS設定をコミットします:

ターミナルで実行
# 変更内容を確認
git status
git diff config/initializers/cors.rb

# CORS設定をコミット
git add config/initializers/cors.rb
git commit -m "CORS設定"

6. RSpecの設定

🧪 テストコードの重要性を再確認

Rails Tutorialでもテストコードを書きましたね。ユーザー登録のテスト、ログインのテスト、マイクロポストの投稿テストなど、機能を実装するたびにテストを書いて、コードが正しく動作することを確認しました。

💡 なぜテストを書くのか?

テストは、あなたが書いたコードが期待通りに動作することを自動的に確認する仕組みです。

例えば、Rails Tutorialで書いたこんなテストを思い出してください:

  • ユーザー登録で、同じメールアドレスは登録できない
  • ログインしていないユーザーは、投稿ページにアクセスできない
  • 投稿を削除すると、本当にデータベースから消える

これらを毎回手動で確認するのは大変ですよね。テストコードがあれば、rails test(今回はrspec)を実行するだけで、全ての機能が正しく動作しているか一瞬で確認できます。

🔄 MinitestからRSpecへ

Rails TutorialではMinitestというテストフレームワークを使いました。今回は業界標準のRSpecを使います。基本的な考え方は同じですが、書き方がより自然で読みやすくなります。

💡 MinitestとRSpecの違い
特徴MinitestRSpec
書き方Rubyの標準的な書き方英語に近い自然な書き方
学習コスト低い(シンプル)やや高い(機能豊富)
採用企業一部多数(業界標準)
# Minitest(Rails Tutorialで書いた書き方)
test "should create todo" do
assert_difference('Todo.count') do
post todos_url, params: { todo: { title: "Test" } }
end
assert_redirected_to todo_url(Todo.last)
end

# RSpec(今回使う書き方 - より読みやすい!)
it "creates a new todo" do
expect {
post todos_url, params: { todo: { title: "Test" } }
}.to change(Todo, :count).by(1)

expect(response).to have_http_status(:created)
end

どちらも「POSTリクエストを送ったらTodoが1つ増える」ことをテストしていますが、RSpecの方が「期待する(expect)」「変化する(change)」という自然な英語で書けます。

🎯 APIサーバーのテストの特徴

Rails Tutorialでは、HTMLページが正しく表示されるかをテストしました。APIサーバーでは、以下のような点をテストします:

  • HTTPステータスコード:200(成功)、401(認証エラー)、404(見つからない)など
  • JSONレスポンスの形式:期待通りのデータ構造か
  • データの内容:正しい値が返されているか
  • 認証・認可:権限のないユーザーがアクセスできないか

これから作るTodoアプリでも、これらの観点でテストを書いていきます。

🔄 テスト駆動開発(TDD)の第一歩

今回のプロジェクトでは、**テスト駆動開発(Test-Driven Development: TDD)**の考え方を取り入れていきます。

💡 TDDの基本サイクル
  1. Red(赤): まずテストを書く → 当然失敗する(実装がないから)
  2. Green(緑): テストが通る最小限のコードを書く
  3. Refactor(リファクタリング): コードをきれいに整理する

この章では、まさにこのサイクルを体験します:

  • ヘルスチェックのテストを書く(Red)
  • コントローラーを実装する(Green)
  • 必要に応じてコードを整理する(Refactor)

🔧 RSpecの初期設定

それでは、実際にRSpecをセットアップしていきます。

🚀 ここから実践開始!

RSpecの初期設定を行います。これによりテスト環境が構築されます。

🔨 実際にやってみましょう! RSpecの初期設定を行います:

ターミナルで実行
# RSpecの初期設定
docker compose exec web rails generate rspec:install

生成されるファイル:

  • .rspec: RSpecの基本設定
  • spec/spec_helper.rb: RSpec全体の設定
  • spec/rails_helper.rb: Rails固有の設定

📝 rails_helper.rbの設定

生成されたファイルをカスタマイズして、より使いやすくしましょう。ここで設定する内容は、テストを効率的に書くためのヘルパーメソッドやデータベースのクリーンアップなど、テスト全体に関わる重要な設定です。

🚀 ここから実践開始!

RSpecの設定ファイルを編集します。以下の内容をそのままコピーして使ってください。

💡 追加する主な設定
  • FactoryBot: テスト用のデータを簡単に作成できるツール
  • DatabaseCleaner: 各テスト後にデータベースをきれいにする
  • Shoulda Matchers: よく使うテストを1行で書けるようにする

🔨 実際にやってみましょう! spec/rails_helper.rbを以下の内容で編集してください:

spec/rails_helper.rb
require 'spec_helper'
ENV['RAILS_ENV'] ||= 'test'
require_relative '../config/environment'

# 本番環境でテストを実行しないようにガード
abort("The Rails environment is running in production mode!") if Rails.env.production?

require 'rspec/rails'

# spec/support配下のファイルを読み込み
Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f }

# マイグレーションの状態をチェック
begin
ActiveRecord::Migration.maintain_test_schema!
rescue ActiveRecord::PendingMigrationError => e
abort e.to_s.strip
end

RSpec.configure do |config|
# FactoryBotのメソッドを使えるように
config.include FactoryBot::Syntax::Methods

# Database Cleanerの設定(テスト後にDBをクリーン)
config.before(:suite) do
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:truncation)
end

config.around(:each) do |example|
DatabaseCleaner.cleaning do
example.run
end
end

# 基本設定
config.fixture_path = Rails.root.join('spec/fixtures')
config.use_transactional_fixtures = true
config.infer_spec_type_from_file_location!
config.filter_rails_from_backtrace!
end

# Shoulda Matchersの設定(テストを簡潔に書ける)
Shoulda::Matchers.configure do |config|
config.integrate do |with|
with.test_framework :rspec
with.library :rails
end
end

🎯 動作確認用のテストを作成

設定が完了したので、実際に動作するテストを書いてみましょう。

🚀 ここから実践開始!

シンプルなヘルスチェックエンドポイントを作成し、テストを書いていきます。

💡 ヘルスチェックエンドポイントとは?

ヘルスチェックは、APIサーバーが正常に動作しているかを確認するための仕組みです。

  • 通常 /health/ping といったパスで提供
  • 単純に {"status": "ok"} のようなレスポンスを返す
  • 監視ツールやロードバランサーが定期的にアクセスして死活監視に使用
  • 本番環境では必須の機能です!

🔨 実際にやってみましょう! まず、テスト用のディレクトリを作成します:

ターミナルで実行
# specディレクトリ内にrequestsディレクトリを作成
docker compose exec web mkdir -p spec/requests

🔨 実際にやってみましょう! spec/requests/health_spec.rbを作成します:

spec/requests/health_spec.rb
require 'rails_helper'

RSpec.describe "Health Check", type: :request do
describe "GET /health" do
it "returns success status" do
get "/health"

expect(response).to have_http_status(:success)
expect(JSON.parse(response.body)).to eq({"status" => "ok"})
end
end
end

🔴 まずテストが失敗することを確認(TDDのRedフェーズ)

TDDの原則に従って、まず実装なしでテストを実行し、失敗することを確認します。

🔨 実際にやってみましょう! まだ実装していない状態でテストを実行します:

ターミナルで実行
# RSpecを実行(まだ実装がないので失敗するはず)
docker compose exec web rspec

期待される出力(エラー):

Health Check
GET /health
returns success status (FAILED - 1)

Failures:

1) Health Check GET /health returns success status
Failure/Error: get "/health"

ActionController::RoutingError:
No route matches [GET] "/health"
💡 なぜ失敗することが重要?

このエラーは「/healthへのルートが存在しない」ことを示しています。これで、テストが正しく書けていることが確認できました。もしテストが最初から成功してしまったら、テスト自体が間違っている可能性があります。

🛣️ ルーティングとコントローラーの作成(TDDのGreenフェーズ)

テストが失敗することを確認できたので、それを通すための実装を追加しましょう。

🚀 ここから実践開始!

テストを通すために、ルートとコントローラーを実装します。

🔨 実際にやってみましょう! テストを通すために、ルーティングとコントローラーを設定します:

config/routes.rb
Rails.application.routes.draw do
# ヘルスチェック用のエンドポイント
get '/health', to: 'application#health'
end
app/controllers/application_controller.rb
class ApplicationController < ActionController::API
# ヘルスチェック用のアクション
def health
render json: { status: 'ok' }
end
end

✅ テストが成功することを確認(TDDのGreenフェーズ完了)

実装が完了したので、先ほど失敗したテストが今度は成功することを確認します。

🚀 ここから実践開始!

RSpecを実行して、テストが通ることを確認します。

🔨 実際にやってみましょう! 再度テストを実行してみましょう:

ターミナルで実行
# RSpecを実行(今度は成功するはず)
docker compose exec web rspec

期待される出力(成功):

Health Check
GET /health
returns success status

Finished in 0.12345 seconds (files took 1.23 seconds to load)
1 example, 0 failures
🎉 TDDサイクルの完了!

おめでとうございます!これでTDDの1サイクルが完了しました:

  • Red: テストを書いて失敗を確認 ✅
  • Green: 最小限の実装でテストを通す ✅
  • Refactor: 今回はシンプルな実装なのでリファクタリングは不要
💡 TDDについての現実

**TDD(テスト駆動開発)**は、開発現場でも意見が分かれる手法です:

賛成派の意見:

  • テストを先に書くことで、要件が明確になる
  • 実装が最小限になり、無駄なコードが減る
  • テストカバレッジが自然と高くなる

慎重派の意見:

  • 開発速度が遅くなることがある
  • 要件が不明確な場合、テストを書きづらい
  • リファクタリング時にテストも修正が必要

このプロジェクトでは:

  • 重要な機能にはテストを書く(必須)
  • TDDを使うかは状況に応じて判断
  • まず動くものを作り、後からテストを追加することもある

大切なのは「テストがあること」であり、「いつ書くか」は柔軟に考えましょう。

🔍 ブラウザでの動作確認

テストが通ったら、実際にブラウザでもアクセスしてみましょう!

🚀 ここから実践開始!

ブラウザで実際にAPIにアクセスして、JSONレスポンスを確認します。

🔨 実際にやってみましょう! サーバーが起動していることを確認して、ブラウザでアクセスします:

ターミナルで実行
# サーバーの状態を確認
docker compose ps

# 起動していない場合は起動
docker compose up -d

ブラウザで以下のURLにアクセス:

http://localhost:3000/health

期待される画面:

{"status":"ok"}

📸 スクリーンショット:ブラウザでhealth エンドポイントにアクセスした結果

💡 curlコマンドでも確認できます
curl http://localhost:3000/health

💾 RSpecとヘルスチェックAPIをコミット

テスト環境とAPIエンドポイントが動作したので、コミットしましょう。

🔨 実際にやってみましょう! RSpec関連の変更をコミットします:

ターミナルで実行
# 変更内容を確認
git status

# RSpec関連とヘルスチェックAPIをコミット
git add .
git commit -m "RSpec追加"

7. 開発用の便利な設定

🛠 Better Errorsの設定

エラーが発生した時に、より詳しい情報を表示してくれる設定を追加します。

🚀 ここから実践開始!

開発を効率化するための設定を追加していきます。

🔨 実際にやってみましょう! config/environments/development.rbに以下を追加してください:

config/environments/development.rb
Rails.application.configure do
# ... 既存の設定 ...

# Better Errorsの設定(開発環境のみ)
# Dockerコンテナ内からのアクセスを許可
BetterErrors::Middleware.allow_ip! "0.0.0.0/0" if defined?(BetterErrors)
end

📏 RuboCopの設定 - コード品質を自動でチェック

🤔 なぜコードスタイルの統一が重要?

チーム開発では、メンバー全員が同じルールでコードを書くことが重要です。人によって書き方が違うと:

  • コードレビューで本質的でない指摘が増える(インデントや改行の位置など)
  • 読みづらいコードになり、バグの温床になる
  • Git の差分が見づらくなる

RuboCopは、Rubyコードの書き方を自動でチェックしてくれるツール(Linter)です。

💡 Linter(リンター)とは?

Linterは、コードの問題を自動的に検出してくれるツールです:

  • 構文エラー: 文法的に間違っているコード
  • スタイル違反: チームで決めたルールに沿っていないコード
  • 潜在的なバグ: 未使用の変数、到達不可能なコードなど
  • 複雑すぎるコード: メソッドが長すぎる、ネストが深すぎるなど

JavaScript では ESLint、Python では Pylint など、各言語に Linter があります。

🔄 RuboCopができること

  1. 問題の検出

    # 悪い例(RuboCopが指摘)
    def calculate_price(items)
    price=0 # スペースがない
    items.each do |item|
    price+=item.price # スペースがない
    end
    return price # 不要なreturn
    end
  2. 自動修正

    # RuboCop実行後(自動修正される)
    def calculate_price(items)
    price = 0
    items.each do |item|
    price += item.price
    end
    price
    end
  3. 複雑度の警告

    • メソッドが長すぎる(10行以上)
    • ABC複雑度が高い
    • 循環的複雑度が高い
🚀 ここから実践開始!

RuboCopの設定ファイルを作成し、実際に実行してみます。

🔨 実際にやってみましょう! .rubocop.ymlを作成します:

.rubocop.yml
# RuboCopの設定ファイル
# チーム全体でコーディングスタイルを統一するため

require:
- rubocop-rails # Rails用のルール
- rubocop-rspec # RSpec用のルール

AllCops:
NewCops: enable # 新しいルールを自動で有効化
Exclude: # チェック対象外のファイル
- 'db/**/*' # マイグレーションファイル
- 'bin/**/*' # 実行ファイル
- 'config/**/*' # 設定ファイル
- 'vendor/**/*' # 外部ライブラリ
- 'spec/spec_helper.rb'
- 'spec/rails_helper.rb'

# クラスやモジュールのコメントは不要
Style/Documentation:
Enabled: false

# frozen_string_literal コメントは不要
Style/FrozenStringLiteralComment:
Enabled: false

# RSpecのブロックは長くなりがち
Metrics/BlockLength:
Exclude:
- 'spec/**/*'
- 'config/routes.rb'

# RSpecのテストで複数のexpectを許可
RSpec/MultipleExpectations:
Enabled: false

# Strong Parametersのテストスタイルを緩和
Rails/StrongParametersExpect:
Enabled: false

🔨 実際にやってみましょう! RuboCopを実行してみましょう:

ターミナルで実行
# コードスタイルをチェック
docker compose exec web rubocop

出力例(違反がある場合):

Inspecting 15 files
.C..C..........

Offenses:

app/controllers/application_controller.rb:3:1: C: Layout/EmptyLineAfterMagicComment: Add an empty line after magic comments.
def health
^

spec/requests/health_spec.rb:7:11: C: Layout/SpaceInsideHashLiteralBraces: Space inside { missing.
expect(JSON.parse(response.body)).to eq({"status" => "ok"})
^

15 files inspected, 2 offenses detected
💡 出力の読み方
  • C: Convention(慣習)違反 - コードスタイルの問題
  • W: Warning(警告)- 潜在的な問題
  • E: Error(エラー)- 構文エラーなど
  • F: Fatal(致命的)- 解析できないコード

🔨 実際にやってみましょう! 自動修正を実行します:

ターミナルで実行
# 自動修正可能な問題を修正(-aオプション)
docker compose exec web rubocop -a

出力例:

Inspecting 15 files
.C..C..........

Offenses:

app/controllers/application_controller.rb:3:1: C: [Corrected] Layout/EmptyLineAfterMagicComment: Add an empty line after magic comments.
spec/requests/health_spec.rb:7:11: C: [Corrected] Layout/SpaceInsideHashLiteralBraces: Space inside { missing.

15 files inspected, 2 offenses detected, 2 offenses corrected
💡 便利なオプション
  • rubocop -a: 安全な自動修正のみ実行
  • rubocop -A: より積極的な自動修正(要注意)
  • rubocop --auto-gen-config: 現在の違反を許可する設定ファイルを生成
  • rubocop app/: 特定のディレクトリのみチェック

🔄 CI/CDとの連携

実際の開発現場では、GitHubにプッシュしたときに自動でRuboCopが実行されるよう設定することが一般的です(CI/CD)。これにより:

  • コードレビュー前に自動でチェック
  • スタイル違反があればマージをブロック
  • チーム全体のコード品質を保証

💾 開発ツールの設定をコミット

Better ErrorsとRuboCopの設定が完了したので、コミットします。

🔨 実際にやってみましょう! 開発ツールの設定をコミットします:

ターミナルで実行
# 変更内容を確認
git status

# 開発ツールの設定をコミット
git add config/environments/development.rb .rubocop.yml
git commit -m "開発ツール設定"

8. GitHubへのプッシュとプルリクエスト

📊 これまでのコミット履歴

第2章では、機能ごとに小さくコミットしてきました。

🔨 実際にやってみましょう! コミット履歴を確認してみましょう:

ターミナルで実行
# コミット履歴を確認
git log --oneline -n 5

期待される出力:

a1b2c3d 開発ツール設定
d4e5f6g RSpec追加
h7i8j9k CORS設定
l0m1n2o Gemfile更新
p3q4r5s 第1章完了
💡 コミットハッシュとは?

a1b2c3dのような文字列はコミットハッシュ(コミットID)と呼ばれます。

  • Gitが各コミットに自動的に付ける一意の識別子
  • 実際は40文字の長い文字列ですが、通常は先頭7文字で表示
  • このIDを使って、特定のコミットに戻ったり、参照したりできます

🌳 ブランチでの作業の進み方

各作業をこまめにコミットすることで、後から「どこで何を変更したか」が一目瞭然になります。

💡 こまめなコミットのメリット
  • 各機能の変更が明確に分かれている
  • 問題があった時に特定のコミットまで戻れる
  • プルリクエストでレビューしやすい

🚀 GitHubリポジトリの作成

最初にGitリポジトリを初期化します。

🔨 実際にやってみましょう! Gitリポジトリを初期化します:

ターミナルで実行
# プロジェクトのルートディレクトリにいることを確認
pwd

# Gitリポジトリを初期化
git init

# 現在の状態を確認
git status

🔨 実際にやってみましょう! GitHubで新しいリポジトリを作成します:

  1. GitHubにログインし、右上の「+」→「New repository」をクリック

GitHubで新規リポジトリを作成

  1. リポジトリ情報を入力:
    • Repository name: todo-api(または任意の名前)
    • Description: 「Rails APIとReactで作るTodoアプリ」(任意)
    • Public/Private: お好みで選択(画像ではPrivateが選択されています)
    • 重要: 「Initialize this repository with」のチェックは全て外す
💡 Private設定について

画像の赤枠部分で「Private」が選択されています。これは:

  • Private: あなたのみ(または招待した人のみ)がアクセス可能
  • Public: 誰でもコードを閲覧可能

学習用なら「Private」で問題ありません。ポートフォリオとして公開したい場合は「Public」を選択しましょう。

  1. 「Create repository」をクリック

  2. 作成後の画面で表示されるコマンドを確認:

既存リポジトリをプッシュするコマンド

📌 赤枠部分について

画像の赤枠部分「...or push an existing repository from the command line」は、すでにローカルにGitリポジトリがある場合のコマンドです。第1章でRailsプロジェクトを作成した時点で、自動的にGitリポジトリも作成されているので、この方法を使います。

🔨 実際にやってみましょう! ローカルのGitリポジトリとGitHubを連携させます:

ターミナルで実行
# GitHubリポジトリをリモートとして追加(URLは自分のものに置き換える)
git remote add origin https://github.com/あなたのユーザー名/todo-api.git

# 現在のブランチ名をmainに変更(まだmasterの場合)
git branch -M main

# リモートリポジトリの設定を確認
git remote -v

🚀 GitHubにプッシュ

🔨 実際にやってみましょう! 作業ブランチをGitHubにプッシュします:

ターミナルで実行
# feature/chapter-2ブランチをプッシュ
git push -u origin feature/chapter-2

初回プッシュ時の出力例:

Enumerating objects: 23, done.
Counting objects: 100% (23/23), done.
...
Branch 'feature/chapter-2' set up to track remote branch 'feature/chapter-2' from 'origin'.

📝 プルリクエストの作成

🔨 実際にやってみましょう! GitHubでプルリクエストを作成します:

  1. ブラウザでGitHubリポジトリを開く
  2. 「Compare & pull request」ボタンをクリック

Compare &amp; pull request

  1. プルリクエストの内容を入力:

Title:

第2章: Rails APIプロジェクトの初期設定

Description:

## 概要
Rails APIモードでプロジェクトの基盤を構築しました。

## 変更内容
- ✅ 必要なGemの追加(認証、CORS、テスト関連)
- ✅ RSpecによるテスト環境の構築
- ✅ CORS設定でフロントエンドからのアクセスを許可
- ✅ 開発効率化ツールの導入(Better Errors、RuboCop)
- ✅ ヘルスチェックエンドポイントの実装

## 動作確認
- [ ] `docker compose up -d` でコンテナが起動すること
- [ ] `http://localhost:3000/health``{"status":"ok"}` が表示されること
- [ ] `docker compose exec web rspec` でテストが通ること

## レビューポイント
- Gemfileの依存関係は適切か
- CORS設定のセキュリティは問題ないか
- テスト環境の設定は十分か

プルリクエスト作成画面

  1. 「Create pull request」ボタンをクリック

✅ マージとmainブランチの更新

プルリクエストが承認されたら(または自分でレビューしたら)、マージします。

💡 実際のチーム開発では

本来、プルリクエストは以下の流れで進みます:

  1. プルリクエストを作成
  2. 他のメンバーがコードをレビュー
  3. 修正が必要ならコメントをもらって修正
  4. 承認(Approve)をもらう
  5. マージする

今回は学習用なので、自分でレビューしてマージしますが、実際の現場では必ず他の人にレビューしてもらいましょう!

🔨 実際にやってみましょう! GitHubでマージ後、ローカルを更新します:

ターミナルで実行
# mainブランチに切り替え
git checkout main

# リモートの最新情報を取得
git fetch origin

# mainブランチを最新に更新
git pull origin main

# 作業が完了したfeatureブランチを削除(オプション)
git branch -d feature/chapter-2
💡 ブランチを削除する理由
  • 完了したブランチは削除してスッキリ管理
  • GitHubには履歴が残るので安心
  • 新しい機能は新しいブランチで開発

📋 まとめ

✅ この章で達成したこと

第2章では以下の内容を学びました:

  • 🌳 Gitブランチの基本を理解し、実際に使えるようになった
  • 🚀 Rails APIモードの特徴と通常モードとの違いを理解した
  • 💎 必要なGemを選定し、それぞれの役割を理解した
  • 🗄️ データベース接続の仕組みと環境変数の重要性を学んだ
  • 🌐 CORSの概念と設定方法を理解した
  • 🧪 RSpecによるテスト環境を構築し、実際にテストを書いた
  • 🔍 ブラウザとコマンドライン両方でAPIの動作確認ができた
  • 📤 プルリクエストの作成からマージまでの流れを体験した

🎯 身についたスキル

  • Gitを使った実践的な開発フロー
  • Rails APIプロジェクトの初期設定
  • Gemの選定と導入
  • テスト駆動開発の第一歩
  • チーム開発で必要なGitHubの使い方

🚀 次のステップ

次章では、この基盤の上に認証機能を実装します。ユーザーのログイン・ログアウトなど、実際のアプリケーションに必要な機能を作っていきます!

🏃 演習問題

理解を深めるために、以下の課題に挑戦してみましょう:

📝 演習1: APIバージョニング

Rails APIでは、バージョン管理が重要です。以下を実装してください:

  1. /api/v1/health というパスでアクセスできるようにルーティングを変更
  2. Api::V1::ApplicationController を作成
  3. テストも合わせて修正
💡 ヒント(クリックで展開)

ルーティングのnamespace:

# config/routes.rb
namespace :api do
namespace :v1 do
# ここにルーティングを書く
end
end

コントローラーの階層:

  • app/controllers/api/v1/ディレクトリを作成
  • モジュール構造に注意
✅ 答え(クリックで展開)
# config/routes.rb
Rails.application.routes.draw do
namespace :api do
namespace :v1 do
get '/health', to: 'application#health'
end
end
end

# app/controllers/api/v1/application_controller.rb
module Api
module V1
class ApplicationController < ActionController::API
def health
render json: { status: 'ok', version: 'v1' }
end
end
end
end

📝 演習2: ヘルスチェックレスポンスの拡張

現在のヘルスチェックAPIに現在時刻を追加してください。

期待されるレスポンス例:

{
"status": "ok",
"timestamp": "2024-01-05T10:30:00+09:00"
}
💡 ヒント(クリックで展開)

現在時刻を取得する方法:

  • Time.current - Railsのタイムゾーン設定を考慮した現在時刻
  • Time.zone.now - 同じくタイムゾーンを考慮(Time.currentと同じ)

JSONレスポンスに含めるには、healthアクションのrenderメソッドに追加します。

✅ 答え(クリックで展開)
# app/controllers/application_controller.rb
class ApplicationController < ActionController::API
def health
render json: {
status: 'ok',
timestamp: Time.current
}
end
end

別解(ISO8601形式で返す場合):

def health
render json: {
status: 'ok',
timestamp: Time.current.iso8601
}
end

📚 参考資料

より深く学びたい方向け:


次章: 第3章: Todo CRUD API(認証なし版)