第34章|今さら学ぶ「環境管理(development / test / production)」
📚 シリーズ目次はこちら → 「今さら学ぶ」シリーズ — はじめに
🗺️ KnowledgeNoteの設計を確認 → 設計マップ
この章でわかること
- development / test / production — 3つの環境の役割と違い
-
config/environments/— 環境ごとの設定ファイルの読み方 -
Rails.env— コードの中で環境を判定する方法 - credentials と環境変数 — 秘密情報の管理方法と使い分け
🏠 たとえ話で掴む「環境管理」
レストランでたとえると、「本番営業」と「仕込み・練習」は同じ厨房でも設定が違います。
本番営業では「本物の食材を使う」「お客さんには失敗を見せない」「会計システムをフル稼働させる」。仕込み中は「食材を無駄にしてもいい」「盛り付けを試行錯誤できる」「会計はスキップ」。
Railsでも同じです。 開発中は素早く動かすための緩い設定、 本番では安全・品質重視の厳格な設定 と、環境ごとに切り替えます。
| レストラン | Railsの環境管理 |
|---|---|
| 本番営業(お客さんあり) | production — 実際のユーザーが使う |
| 仕込み・練習(スタッフのみ) | development — 手元で開発 |
| 衛生検査のシミュレーション | test — 自動テストの実行 |
環境管理とは何か — 技術的な定義
3つの環境
Railsには標準で3つの環境があります。
| 環境 | 名前 | 用途 |
|---|---|---|
| development | 開発環境 | 手元で開発するとき |
| test | テスト環境 | RSpecなどのテスト実行時 |
| production | 本番環境 | 実際にユーザーに公開するとき |
RAILS_ENV 環境変数でどの環境で動かすかを指定します。rails server はデフォルトで development、テスト実行時は test、Renderなど本番サーバでは production になります。
3つの環境で何が違うか
| 設定 | development | test | production |
|---|---|---|---|
| ログレベル | debug(詳細) | debug | info(最小限) |
| キャッシュ | 無効 | 無効 | 有効 |
| アセット | 都度読み込み | 都度読み込み | 事前コンパイル |
| エラー表示 | 詳細エラー画面 | 例外を raise | カスタムエラーページ |
| メール | letter_opener | 実際には送らない | 実際に送信 |
| DB名のサフィックス | _development |
_test |
本番DB |
| コード自動リロード | あり | なし | なし |
| SSL強制 | なし | なし | あり |
📁 config/environments/ — 環境別設定ファイル
config/
├── application.rb ← 全環境共通の設定
└── environments/
├── development.rb ← 開発環境のみの設定
├── test.rb ← テスト環境のみの設定
└── production.rb ← 本番環境のみの設定
development.rb のよく使う設定
# config/environments/development.rb
Rails.application.configure do
# コードを変更しても再起動不要(自動でリロード)
config.enable_reloading = true
# エラー時に詳細なスタックトレースを画面に表示
config.consider_all_requests_local = true
# キャッシュを無効化(`rails dev:cache` でON/OFFできる)
config.action_controller.perform_caching = false
# メールはブラウザで確認(実際には送らない)
config.action_mailer.delivery_method = :letter_opener_web
# ログを詳細に出力(SQLも全て表示)
config.log_level = :debug
# N+1検出ツール(→ [第24章](https://qiita.com/harapeco-mgn/items/fc2ffbd0035b8f9f3a39))
config.after_initialize do
Bullet.enable = true
Bullet.rails_logger = true
end
end
production.rb のよく使う設定
# config/environments/production.rb
Rails.application.configure do
# コードの自動リロードをしない(パフォーマンス向上)
config.enable_reloading = false
# エラーの詳細をユーザーに見せない(カスタムエラーページを使う)
config.consider_all_requests_local = false
# キャッシュを有効化(→ [第24章](https://qiita.com/harapeco-mgn/items/fc2ffbd0035b8f9f3a39))
config.action_controller.perform_caching = true
config.cache_store = :solid_cache_store
# HTTPSを強制
config.force_ssl = true
# ログはinfoレベルのみ(debugは出さない)
config.log_level = :info
# プリコンパイル済みアセットを配信
config.public_file_server.enabled = true
end
test.rb の特徴
# config/environments/test.rb
Rails.application.configure do
# テスト専用DBを使う(database.yml の test: セクション)
# → 本番・開発DBには絶対に触れない
# テスト中はメールを実際に送らず、テストコードで内容を検証できる
config.action_mailer.delivery_method = :test
# 例外を raise するので、テストがクラッシュして失敗する
config.consider_all_requests_local = true
config.action_dispatch.show_exceptions = :rescuable
end
🚨 本番のエラーページをカスタマイズする(404 / 500)
production.rb で config.consider_all_requests_local = false にすると、エラー時に詳細なスタックトレースはユーザーに見せなくなります。代わりに表示されるのが エラーページ です。
デフォルトのエラーページ
Railsはデフォルトで public/ に静的なHTMLファイルを用意しています。
public/
├── 404.html ← リソースが見つからない(RecordNotFound 等)
├── 422.html ← CSRF検証失敗等
└── 500.html ← サーバ内部エラー
これらは 静的HTMLファイル なので、アプリのレイアウト(ナビバーなど)は適用されません。デザインを統一したい場合は、Railsのルーティングで動的に返す設定にします。
Railsのルーティングでエラーページを返す
# config/application.rb
config.exceptions_app = self.routes
# config/routes.rb
match "/404", to: "errors#not_found", via: :all
match "/422", to: "errors#unprocessable", via: :all
match "/500", to: "errors#internal_server_error", via: :all
# app/controllers/errors_controller.rb
class ErrorsController < ApplicationController
# 認証チェックを飛ばす(ログアウト中でもエラーページを表示する)
skip_before_action :authenticate_user!, raise: false
def not_found
render status: :not_found
end
def unprocessable
render status: :unprocessable_entity
end
def internal_server_error
render status: :internal_server_error
end
end
<%# app/views/errors/not_found.html.erb %>
<div class="text-center py-20">
<h1 class="text-6xl font-bold text-gray-300 mb-4">404</h1>
<p class="text-xl text-gray-600 mb-8">ページが見つかりません</p>
<%= link_to "トップに戻る", root_path,
class: "bg-blue-600 text-white px-6 py-2 rounded" %>
</div>
💡
config.exceptions_app = self.routesを設定しても、development環境では詳細エラー画面が優先されます。開発中に本番のエラーページを確認したい場合は、config/environments/development.rbでconfig.consider_all_requests_local = falseに変更します。
🔑 Rails.env — コードの中で環境を判定する
Rails.env を使うと、実行中の環境をコードの中から判定できます。
# 環境を確認する
Rails.env # => "development" / "test" / "production"
Rails.env.development? # => true / false
Rails.env.test? # => true / false
Rails.env.production? # => true / false
使用例:初期データを開発環境でのみ投入する
# db/seeds.rb
if Rails.env.development?
# 開発用ダミーデータ(Faker)— 本番では実行しない
Faker::Config.locale = 'ja' # 日本語名を生成するためにロケールを設定
100.times do
User.create!(
name: Faker::Name.name, # => "佐藤 太郎"(ja ロケール時)
email: Faker::Internet.unique.email
)
end
end
# 本番・開発共通の初期データ(管理者アカウント等)
User.find_or_create_by!(email: "admin@example.com") do |user|
user.name = "管理者"
user.password = Rails.application.credentials.admin_password
end
使用例:本番環境でのみ外部サービスに送信する
# app/services/notification_service.rb
def notify(message)
if Rails.env.production?
# 本番でのみ Slack に通知を送る
SlackNotifier.send(message)
else
# 開発・テストではログに出すだけ
Rails.logger.info "[Notification] #{message}"
end
end
💡 テストコードに
Rails.env.production?を書かない
テストコード内で環境を判定する条件分岐を使うと、テストの信頼性が落ちます。代わりにスタブやモックを使います(→ 第22章)。
🔐 credentials と環境変数 — 秘密情報の管理
APIキーやDB接続情報など、コードに直書きしてはいけない情報を 秘密情報 と呼びます。Gitリポジトリに入れてしまうと、GitHubに公開したときに外部から見えてしまいます。
2つの管理方法
| 方法 | 仕組み | 向いている場面 |
|---|---|---|
| credentials | 暗号化ファイル + 復号キーをセットで管理 | チームでGit経由で秘密情報を共有したい |
| 環境変数 | サーバやCI/CDツールに直接設定する変数 | Render/HerokuなどのPaaSを使う |
credentials の使い方
# 暗号化ファイルを編集する(エディタが開く)
$ EDITOR=vi rails credentials:edit
# config/credentials.yml.enc(編集画面のイメージ)
aws:
access_key_id: AKIAIOSFODNN7EXAMPLE
secret_access_key: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
jwt_secret_key: "my-super-secret-jwt-key-change-this"
resend_api_key: "re_xxxxxxxxxxxxxxxxxxxx"
admin_password: "initial-admin-password"
# コードからの読み出し
Rails.application.credentials.aws[:access_key_id]
Rails.application.credentials.jwt_secret_key
Rails.application.credentials.resend_api_key
credentialsのファイル構成:
| ファイル | Gitに含める | 説明 |
|---|---|---|
config/credentials.yml.enc |
✅ 含める | 暗号化済みなので安全 |
config/master.key |
❌ 含めない | 復号キー。流出したら全て読まれる |
master.key は .gitignore にデフォルトで記載されているので、意図的に追加しない限りGitに含まれません。チームで共有する場合は、Slack や 1Password などの安全な手段で渡します。
環境変数の使い方(RenderやHerokuの場合)
クラウドサービスを使う場合は、ダッシュボードで環境変数を設定するのが一般的です。
# Rails から環境変数を読む
ENV["DATABASE_URL"]
ENV["RAILS_MASTER_KEY"]
ENV["STRIPE_SECRET_KEY"]
# config/environments/production.rb での例
config.action_mailer.smtp_settings = {
user_name: ENV["SMTP_USERNAME"],
password: ENV["SMTP_PASSWORD"],
address: ENV["SMTP_ADDRESS"]
}
どちらを使うか
credentials を使う → チーム開発でGit経由で秘密情報を共有したい場合
環境変数を使う → Render/Herokuなどのダッシュボードで設定する場合
両方混在させると管理が大変になるので、プロジェクトで統一する。
本シリーズ(KnowledgeNote)では credentials を基本にしている。
🛠️ KnowledgeNoteでの具体例
環境ごとのメール設定
# config/environments/development.rb
# 開発中はブラウザでメール内容を確認(実際には送らない)
config.action_mailer.delivery_method = :letter_opener_web
config.action_mailer.default_url_options = { host: "localhost", port: 3000 }
# config/environments/test.rb
# テスト中はメールを送らずキューに溜める(RSpecで内容を検証できる)
config.action_mailer.delivery_method = :test
# config/environments/production.rb
# 本番では実際にResend経由でメールを送る(→ [第29章](https://qiita.com/harapeco-mgn/items/420a7d80595504b0444d))
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
address: "smtp.resend.com",
port: 587,
user_name: "resend",
password: Rails.application.credentials.resend_api_key,
authentication: :plain,
enable_starttls_auto: true
}
config.action_mailer.default_url_options = {
host: Rails.application.credentials.app_host
}
環境ごとのActive Storage設定(→ 第30章)
# config/environments/development.rb
config.active_storage.service = :local # ローカルのディスクに保存
# config/environments/production.rb
config.active_storage.service = :amazon # S3に保存
💼 面接で聞かれたら?
Q:Railsの3つの環境(development / test / production)の違いを教えてください。
「developmentは手元で開発するための環境で、コードの変更を自動検知したりエラーの詳細を画面に表示します。testはRSpec等のテスト実行用で、テスト専用のDBを使い本番データには触れません。productionは実際のユーザーが使う環境で、キャッシュを有効にしてパフォーマンスを上げ、エラーの詳細は隠してカスタムページを表示します。
config/environments/ディレクトリの各ファイルで設定を分けています。」深掘りされたら:
- 「credentialsとは?」→ 秘密情報(APIキー等)を暗号化してGitで管理する仕組み。
credentials.yml.encをmaster.keyで復号して読む。master.keyはGitに含めない。- 「本番と開発で動作が違ったときの原因は?」→
config/environments/の設定差異が多い。キャッシュの有無、アセットの読み方、ログレベル、メール設定の違いが原因になることがある。- 「テストが本番と同じ環境で動かないのはなぜ?」→ テスト環境は専用DBを使い、本番データには触れないよう意図的に分離されている。
🔗 もっと深く知りたい人へ(1次情報リンク)
- Rails ガイド:Rails の設定 — 全設定項目の詳細
- Rails ガイド:セキュリティ(credentials) — credentials の仕組みと使い方
- Ruby公式リファレンス:ENV — 環境変数の読み書き
まとめ
- ✅ development / test / production の3環境がある。
RAILS_ENVで切り替え、rails serverはデフォルトでdevelopment - ✅
config/environments/の各ファイルで環境ごとの設定を分離する - ✅
Rails.env.production?でコードの中から環境を判定できる - ✅ 秘密情報は credentials(暗号化ファイル)または環境変数で管理。
master.keyは絶対にGitに含めない - ✅ テスト環境は専用DBで動く。本番データには触れない
- ✅ 本番の404/500ページは
config.exceptions_app = self.routesでRailsのビューとして返せる
📚 シリーズ目次:「今さら学ぶ」シリーズ — はじめに