Claude CodeでRailsアプリを開発する手順とscaffoldの使い分け
Claude CodeでRailsアプリを開発する手順を解説します。モデルやコントローラーの実装、rails generate scaffoldとの使い分けが分かります。
Claude CodeでRailsアプリを開発するとは
Claude CodeでRailsアプリを開発するとは、rails newやbin/rails generateといったRailsコマンドをClaude Codeのターミナルセッション内で実行する進め方です。モデル・ビュー・コントローラーの実装を、エージェントに任せられます。
Railsアプリ自体はMVC(Model・View・Controller)で構成されます。モデルはデータベースのテーブルを、ビューはHTML・JSONなどのレスポンス生成を、コントローラーはリクエストごとの処理をそれぞれ担当します。Claude Codeは、この3層にまたがる変更を一度の指示でまとめて頼める点が、コード補完ツールとの使い勝手の違いになりそうです。
プロジェクトルートのCLAUDE.mdは、セッション開始のたびに読み込まれます。モデル名は単数形、テーブル名は複数形といったRailsの命名規約や、テストの実行コマンドを書いておけば、生成のたびに同じ指示を繰り返さずに済みます。ElixirのPhoenixなら、検証コマンドが生成物に入っている例をPhoenixのmix precommitで扱っています。
開発を始める前の準備
開発を始める前に、Ruby・Rails・Claude Codeの3つを用意します。RailsのGetting Startedガイドが前提とするバージョンは次のとおりです。
| 項目 | 必要バージョン |
|---|---|
| Ruby | 必要バージョン3.2以降 |
| Rails | 必要バージョン8.1.0以降 |
| コードエディタ | 必要バージョン任意 |
Rails自体がインストール済みかは、次のコマンドで確認できます。ガイドの想定出力はRails 8.1.0で、それ以上のバージョンが出れば要件を満たします。
rails --versionmacOSに最初から入っている/usr/bin/rubyは古く、ruby -vがruby 2.6.10p210と表示される環境があります。この状態でrails --versionを打つと、Railsが未導入であることを知らせるメッセージが返ります。Rubyが3.2未満のときは、Railsを入れる前にRuby側を3.2以降へ上げます。
Claude Codeはネイティブインストーラーで導入します。macOS・Linux・WSLでは以下のコマンドを実行し、インストール後にclaude --versionでバージョンを確認します。
curl -fsSL https://claude.ai/install.sh | bash
claude --version初回はclaudeコマンドを実行するとブラウザでの認証を求められます。ANTHROPIC_API_KEY環境変数を設定している場合は、ログイン画面の代わりにキーの承認を求められる点が異なります。
Rails向けのCLAUDE.mdを置く
rails newで作ったアプリの直下に、次のようなCLAUDE.mdを置くと、毎回の指示が短くなります。公式のメモリ機能の説明では、1ファイル200行以内が目安で、長くなるほどコンテキストを圧迫して遵守率も下がるとされています。
# store(Rails 8.1)
- Railsコマンドはシステムの`rails`ではなく`bin/rails`で実行する
- テストは`bin/rails test`。生成後は`bin/rails db:migrate`の前にマイグレーションの中身を確認する
- モデルは単数形、テーブルとresourcesは複数形で書く
- `db:drop`・`db:reset`・`db:schema:load`は実行しない最後の1行は指示でしかなく、実行を止める仕組みではありません。確実に止めたいコマンドは、後述するdenyルールに書きます。
アプリの規模が大きく、テーブル設計や画面遷移を先に固めたいときは、いきなり生成コマンドを打つのではなく仕様を先に固める進め方も選べます。cc-sddでClaude Codeの仕様駆動開発を実践するは、この段取りを具体的に扱っています。ローカルにRubyを入れずコンテナで開発したい場合は、Docker/Podman/Kubernetes MCPの選び方が開発環境の選定に役立ちます。
ステップ1: Railsアプリの雛形をClaude Codeに作らせる
rails newはRailsアプリの土台一式を生成するコマンドです。ここでは公式ガイドに倣い、storeという名前のシンプルなECアプリを作ります。
rails new store
cd storerails new --helpを見ると、--skip-active-storageのようなフラグで不要な機能を外せます。公式のコマンドラインガイドによれば、Active Storageを外すと依存するAction MailboxとAction Textも一緒に外れます。
生成後はstoreディレクトリの中でclaudeコマンドを実行し、Claude Codeのセッションを開始します。app/にモデル・ビュー・コントローラーが、config/にルーティングとデータベースの設定がまとまっています。以降のステップは、このディレクトリ内でClaude Codeに指示を出す形で進めます。
データベース作成とサーバー起動は次の2つのコマンドで行います。アプリ内のコマンドを実行するときは、システム全体のrailsではなく、アプリのbin/railsを使う書き方で統一します。
bin/rails db:create
bin/rails serverhttp://localhost:3000を開くと、Railsの初期ページが表示されます。開発中はファイルの変更が自動で検知され再読み込みされるため、サーバーを都度再起動する必要はありません。
ステップ2: モデルとマイグレーションを生成する
商品を表すProductモデルを追加します。Claude Codeに「name属性を持つProductモデルを追加して」と指示すると、内部的には次のコマンドが実行されます。
bin/rails generate model Product name:stringこのコマンドはdb/migrate/にマイグレーションファイル、app/models/product.rbにモデルクラス、加えてテストとフィクスチャのファイルを生成します。モデル名は単数形(Product)、対応するデータベースのテーブル名は複数形(products)になる点がRailsの規約です。
マイグレーションのファイル名は、先頭に生成時刻の数字が付いた20250919150856_create_products.rbのような形です。Claude Codeが生成したあとで内容を人が確かめるときは、このファイルを開けば、これから作られるテーブルと列がそのまま読めます。
生成されたマイグレーションを実際のデータベースに反映するには、次のコマンドを実行します。
bin/rails db:migrateマイグレーションを間違えて実行してしまった場合は、bin/rails db:rollbackで直前の変更を取り消せます。反映後はbin/rails consoleを起動し、Product.column_namesを実行すると、データベースの列情報からClaude Codeが定義した属性を確認できます。大きなテーブルを持つ本番向けのマイグレーションは、strong_migrationsの指摘をClaude Codeに直させる手順で事前に検査できます。
ステップ3: コントローラーとルーティングを実装する
次にコントローラーとルーティングを追加します。config/routes.rbにresources :productsを1行書くだけで、一覧・詳細・作成・更新・削除に対応するRESTfulなルートがまとめて定義されます。
Rails.application.routes.draw do
root "products#index"
resources :products
endルートはすでに定義済みのため、コントローラー生成では--skip-routesフラグを付けて、個別ルートが足されるのを避けます。
bin/rails generate controller Products index --skip-routesこのコマンドはコントローラーだけでなく、app/views/products/index.html.erbというビューの雛形、ヘルパー、テストも生成します。公式ガイドの出力では、雛形のビューはProducts#indexという見出しと、ファイルの場所を示す一文だけの内容です。
生成されたProductsControllerのindexアクションは空のメソッドです。ここにデータベースへの問い合わせを1行加えると、ビューへデータを渡せるようになります。
class ProductsController < ApplicationController
def index
@products = Product.all
end
endビュー側では、コントローラーが設定したインスタンス変数@productsをERB(Embedded Ruby)でループし、商品名を表示します。ここまでの3ステップでMVCの最小構成が動く状態になります。
scaffoldとresource、個別生成はどう使い分けるか
ここまではモデル・コントローラー・ルーティングを1つずつ生成しました。Railsにはこれを一括で行う生成コマンドもあり、生成物の量が違います。
3つの生成の仕方
個別に生成
generate modelとgenerate controllerを分けて打ちます。コントローラーにはアクション名を渡した分のビューの雛形が付き、ルーティングは--skip-routesで外せます。CRUDの中身は自分で組み立てる形です。
resource
モデル・マイグレーション・空のコントローラー・ルーティング・テストを生成します。ビューは作らず、コントローラーにCRUDのメソッドも入りません。公式ガイドはAPIを書く場合や、コントローラーのアクションを手で足したい場合に向くとしています。
scaffold
モデル・マイグレーション・コントローラー・ルーティング・テストに加え、一覧・詳細・新規・編集のビューとJSON用のビューまで生成します。プロトタイプを素早く動かしたい場面に向きます。
scaffoldの実行例は次のとおりです。
bin/rails generate scaffold post title:string body:textこのコマンドでpostsテーブルのマイグレーションから各ビューまで生成されます。bin/rails db:migrateのあとでhttp://localhost:3000/postsを開けば、一覧・作成・編集・削除をその場で試せます。scaffoldが生成するテストファイルは雛形のままなので、テストケースは自分で書き足す必要があります。
Claude Codeへの指示で使い分けます。「Product用にscaffoldを生成して」と伝えれば一括生成です。「モデルとルーティングだけ先に作って、コントローラーは後で相談したい」と伝えれば個別生成になります。既存アプリのRailsを上げる場合はClaude CodeでRailsをアップグレードする手順を参照してください。
Claude Codeにbin/railsコマンドの実行権限を渡す
Claude CodeはBashツールでbin/railsコマンドを実行しますが、実行のたびに確認を求められるとテンポが落ちます。v2.1.283以降では、権限モードを設定していない対話セッションはプランを問わずautoモードで始まります。分類器がコマンドの安全性を判断し、多くのコマンドを確認なしで実行します。ただし対応モデルを使い、組織設定で無効化されていない場合の話です。v2.1.283より前は、Pro・Max・Teamプランでだけautoが既定でした。
より細かく制御したい場合は、プロジェクト直下の.claude/settings.jsonに許可・拒否ルールを書きます。
{
"permissions": {
"allow": [
"Bash(bin/rails generate *)",
"Bash(bin/rails db:migrate)",
"Bash(bin/rails test *)"
],
"deny": [
"Bash(bin/rails db:drop*)",
"Bash(bin/rails db:reset*)",
"Bash(bin/rails db:schema:load*)",
"Bash(bin/rails db:seed:replant*)"
]
}
}ルール中の*はサブコマンドより後ろに置きます。Bash(bin/rails generate *)はgenerate配下のコマンドだけを許可し、Bash(bin/rails *)のように書くとdb:dropを含むすべてのbin/railsコマンドが許可されます。*の直前の半角スペースもルールの一部です。Bash(bin/rails test *)はbin/rails test単体にも一致します。スペースなしのdb:drop*と書いたのは、db:drop:allのような派生タスクまで拒否に含めるためです。
拒否ルールは、同じ呼び出しに一致する許可ルールより常に優先されます。データを失う代表的な操作は、db:dropのほかに3つあります。db:resetは現在の環境のデータベースをスキーマから作り直し、シードも読み込みます。db:schema:loadはスキーマファイルから作り直し、db:seed:replantはテーブルを空にして初期データを入れ直します。上のdenyはこの4つを並べています。
ルールはコマンドの文字列に対して一致します。rails db:dropやbundle exec rails db:dropはbin/rails db:dropとは別の文字列なので、別のルールが要ります。CLAUDE.mdでbin/railsを使うよう書いたのはこのためです。
コマンドラインから一時的に許可する
設定ファイルを書き換えず、1回のセッションだけルールを渡すこともできます。v2.1.289のclaude --helpには、権限モードの選択肢がacceptEdits・auto・bypassPermissions・manual・dontAsk・planと表示されます。許可ルールは--allowedToolsで、ヘルプの例は"Bash(git *) Edit"のようにスペース区切りです。
claude --permission-mode auto --allowedTools "Bash(bin/rails generate *)" "Bash(bin/rails test *)"生成のたびに回す確認サイクル
権限を緩めるほど、生成物を人が確かめる工程が重要になります。次の4段階を1サイクルにしておくと、Claude Codeが出した変更を見落としにくくなります。
生成から反映までの確認サイクル
- 1
--pretendで生成内容を先に見る
ファイルを作らずに、どのファイルが生成されるかを一覧します。
createとrouteの行が想定どおりかを見ます。 - 2
生成して差分を確かめる
生成後に
git statusでファイルの増減を、git diffで既存ファイルの変更を確かめます。config/routes.rbは既存ファイルなので、差分として現れます。 - 3
マイグレーションを読んでから反映する
db/migrate/の新しいファイルでテーブル名と列の型を確かめ、bin/rails db:migrateを実行します。 - 4
テストで挙動を確かめる
bin/rails testを実行し、生成されたテストの中身と結果を確かめます。
CIやリモートの開発機からClaude Codeにbin/rails testを実行させたい場合は、Claude apps gatewayをCIやリモート開発機から使うにはがゲートウェイ経由の接続方法をまとめています。
よくあるつまずき
生成コマンドのタイプミスに気づかず実行してしまう
ProductのつもりでArtcleのように打ち間違えると、誤った名前のファイル一式が生成されます。bin/rails destroyはgenerateの逆で、実行済みの生成コマンドが作ったファイルを自動で判別して削除します。bin/rails dという別名でも呼べます。
bin/rails destroy model Artcle title:string body:textdestroyは上のallowルールに含まれないため、権限モードによっては確認が入ります。db:migrateを実行したあとなら、destroyの前にbin/rails db:rollbackでテーブルを戻しておくと、削除したマイグレーションの痕跡がデータベースに残りません。
マイグレーションを作っただけで反映を忘れる
generate modelはマイグレーションファイルを作るだけで、データベースへの反映は別操作です。bin/rails db:migrateを実行し忘れると、コンソールやビューで「テーブルが存在しない」というエラーになります。
単数形と複数形を取り違える
モデルクラスは単数形(Product)、データベースのテーブル名やルーティングのresourcesは複数形(products)で書きます。逆にすると生成コマンドが想定と異なるファイル名・テーブル名を作ってしまいます。
--skip-routesを忘れてルートが二重になる
resources :productsですでにルートを定義済みの状態でgenerate controllerを素のまま実行すると、ルーティングの生成もあわせて走ります。結果としてconfig/routes.rbにget 'products/index'のような個別ルートが足され、resources :productsと二重に定義されます。
生成コマンドが既存ファイルを上書きしてしまう
bin/rails generateには、既存ファイルを上書きする-f(--force)と、既存ファイルを飛ばす-s(--skip)があります。Bash(bin/rails generate *)は--force付きの呼び出しにも一致するため、許可ルールだけではこの上書きを止められません。手で編集済みのモデルやコントローラーに再度generateをかけるときは、先に--pretendで対象ファイルを確かめ、Gitで変更をコミットしてから実行します。
まとめ
生成の単位は、個別生成、resource、scaffoldの順に広がります。任せる範囲が広いほど、確かめる量も増えます。
scaffoldまで任せるなら--pretendとgit diffを毎回挟み、個別生成なら変更が小さいぶん確認も短く済みます。許可ルールをどこまで緩めるかは、その単位に合わせて決められます。
ローカルでの実装が固まった後にHerokuへデプロイするなら、Heroku MCPサーバーでClaude Codeからアプリをデプロイ・スケーリングするが手順を扱っています。
参照した一次ソース
この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。