routing-patterns について
routing-patternsは、AIエージェントがRailsのルートをレビュー、生成、更新するためのスキルです。再利用可能なconcernや浅いネストなど、保守しやすいルート構成を扱います。
主な機能
- 01再利用可能なルートconcern
- 02浅いネストのルート
- 03アクションの明示的な制限
- 04ネスト・単数リソース
- 05カスタムパラメーターとリゾルバー
- 06制約に基づくルーティング
活用シーン
- 01Railsのルートファイルのレビュー
- 02再利用可能なリソースルートの生成
- 03深いネストURLの短縮
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ rolemodel/ rolemodel-skills --skill routing-patternsインストール後、Claude Code で/routing-patternsを入力して読み込まれたか確認します。
詳細
ルートのベストプラクティス
目的
このスキルは、プロフェッショナルなパターンとベストプラクティスに従って Rails のルートをレビュー、生成、更新する AI エージェントを支援します。RESTful なリソースルーティング、コード再利用のためのルートの concern、浅いネストの戦略、あらゆる Rails アプリケーションに適用できる高度なルート設定について説明します。
コンテキスト
このスキルでは、以下を扱います。
- RESTful な規約に基づく Rails のルーティング
- DRY(Don't Repeat Yourself)の原則を実現するルートの concern
- URL が長くなりすぎないようにする浅いネスト
- 柔軟なルーティングのためのカスタムパラメーターとメタデータ
- ポリモーフィックなパスのためのカスタムルートリゾルバー
- 認可のための制約ベースのルーティング
- 保守しやすいルートファイルのための整理パターン
ベストプラクティス
1. 再利用可能な振る舞いのためのルートの concern
複数のリソースで共有される振る舞いについては、routes.rb の先頭に concern を定義します。これにより、ルートを DRY に保ち、保守しやすくなります。
例:コメント可能なリソース
concern :commentable do
resources :comments, commentable_type: parent_resource.name.classify
end
例:複製可能なリソース
concern :duplicatable do
resources :duplications, only: %i[create], resource_type: parent_resource.name.classify
end
動的フォームでは、turbo_form gem のエンジンが定義する :turbo_form concern を使用します。定義せずに適用してください。詳しくは dynamic-forms スキルを参照してください。
重要なポイント:
- concern を使うと、共通するネストされたリソースのパターンを再利用可能なモジュールに切り出せます
parent_resource.name.classifyを使って、親のコンテキストの型をコントローラーに動的に渡します- 適切な場合は
only:またはexcept:を指定して、アクションを制限します - カスタムパラメーター(
commentable_type、resource_typeなど)は、コントローラーにメタデータとして渡されます - コントローラーは
rolemodel_railsgem(>= 2.4.0)が提供するresource_for(:commentable_type)を使って、そのメタデータを親レコードに戻します
コントローラーを作成する前に、polymorphic-parent-resources スキルを参照してください。 *_type のデフォルト値を渡すだけでは、パターンの半分にすぎません。このスキルでは、コントローラー側の処理、浅いネストで必要となる before_action のスコープ設定(メンバールートでは誤った *_type が引き継がれます)、既存の親ごとのコントローラーを統合する方法について説明しています。
2. リソースへの concern の適用
concerns: オプションにシンボルの配列を指定して、concern を適用します。
resources :products, concerns: %i[duplicatable turbo_form]
resources :articles, concerns: %i[commentable duplicatable turbo_form]
メリット:
- 繰り返し記述していたネストされたリソース定義をなくせます
- 共有する振る舞いを変更する際、更新が必要なのは一箇所だけです
- どのリソースが共通の機能を共有しているかが一目でわかります
3. 浅いネストの戦略
scope shallow: true のラッパーを使って、すべてのネストされたリソースで浅いネストを有効にします。これにより、深くネストしたときに URL が扱いにくくなるのを防げます。
scope shallow: true do
resources :projects do
resources :tasks do
resources :comments
# comments routes are shallow - only :index and :create are nested
# show/edit/update/destroy use /comments/:id instead of /projects/:project_id/tasks/:task_id/comments/:id
end
end
end
end
メリット:
- メンバーアクション(show、edit、update、destroy)の URL が短く、わかりやすくなります
- コレクションアクション(index、create)だけが親の下にネストされたままになります
- 個々のリソースの URL をブックマークしたり、共有したりしやすくなります
- 完全なネストが必要な場合は
shallow: falseで上書きできます
生成されるルート:
# Nested (collection routes)
GET /projects/:project_id/tasks tasks#index
POST /projects/:project_id/tasks tasks#create
GET /projects/:project_id/tasks/new tasks#new
# Shallow (member routes)
GET /tasks/:id tasks#show
GET /tasks/:id/edit tasks#edit
PATCH /tasks/:id tasks#update
DELETE /tasks/:id tasks#destroy
上書きの例:
concern :assembly do
# Keep full nesting when parent context is always needed
resources :assembly_items, only: %i[show], param: :kind, shallow: false
end
注意点 — 浅いメンバールートと親ごとのデフォルト値。 メンバーアクションを含む concern を複数の親に適用すると、Rails は浅いメンバーパス(/tasks/:id)を親ごとに生成します。ルート名が付くのは最初のルートだけで、残りは到達できない重複ルートになります。そのため、commentable_type など、その concern に設定したカスタムデフォルト値は、実際のレコードの親にかかわらず、すべてのメンバーリクエストで最初に生成された親を指します。コントローラーでは、メンバーアクションの *_type パラメーターを参照してはいけません。before_action のスコープをコレクションアクションのみに限定してください。polymorphic-parent-resources を参照してください。
4. only: と except: によるアクションの制限
リソースが提供するアクションを必ず明示してください。これにより、セキュリティ、パフォーマンス、コードの明確さが向上します。
# Only specific actions
resources :duplications, only: %i[create] # Only create action needed
resources :previews, only: %i[show update] # Only show and update
# All except specific actions
resources :automations, except: %i[show] # All standard actions except show
resources :notes, except: %i[show] # Create/edit/destroy but no individual view
resources :widgets, except: %i[index show] # No collection or individual views
重要な理由:
- 未使用のルートが
rails routesの出力に含まれるのを防ぎます - 実装されていないコントローラーアクションへのアクセスをブロックします
- 他の開発者に意図を明確に伝えます
- 不要なエンドポイントを公開せず、攻撃対象領域を減らします
5. ネストされたリソース
親に属するリソースは、適切にネストしてください。
resources :companies do
resources :employees, except: %i[index show]
end
resources :products do
resources :reviews, except: %i[index]
resources :variants, except: %i[index show]
end
一般的なパターン:
- 親リソースはデフォルトで完全な CRUD を持ちます
- ネストされたリソースでは、多くの場合
indexを除外します(親の show ページに表示されます) - ネストされたリソースでは、多くの場合
showを除外します(インラインで編集するか、親のビューから編集します) - ネストされたリソースの create/update/destroy アクションは、親のコンテキスト内で動作します
6. 単数リソース
親ごとに 1 つしか存在しないリソースには、単数形の resource を使用します。
resources :users do
resource :profile, only: %i[show edit update] # Only one profile per user
resource :settings, only: %i[edit update] # Only one settings per user
resource :avatar, only: %i[show update] # Only one avatar per user
end
重要なポイント:
- 単数リソースには
indexアクションがありません - URL に
:idパラメーターは不要です(例:/users/1/profiles/1ではなく/users/1/profile) - 1 対 1 の関連やシングルトンリソースに最適です
7. コレクションルートとメンバールート
on: :collection または on: :member を使ってカスタムルートを追加します。
resources :products do
# Collection routes (no :id needed)
get :search, on: :collection # /products/search
post :bulk_import, on: :collection # /products/bulk_import
# Member routes (requires :id)
post :duplicate, on: :member # /products/:id/duplicate
patch :archive, on: :member # /products/:id/archive
get :preview, on: :member # /products/:id/preview
end
# In a concern
concern :archivable do
patch :archive, on: :member
patch :unarchive, on: :member
end
重要なポイント:
- コレクションルートはコレクション全体を対象とします(
:idパラメーターなし) - メンバールートは単一のリソースを対象とします(
:idパラメーターが必要) - 適切な HTTP 動詞を使用します(読み取りは GET、作成は POST、更新は PATCH/PUT、削除は DELETE)
8. カスタムパラメーター
param: を使ってデフォルトのパラメーター名を上書きします。
resources :products, param: :slug # Uses :slug instead of :id
# In concerns
concern :categorizable do
resources :categories, only: %i[show], param: :slug
end
結果:
- URL は
/products/:idではなく/products/:slugになります - コントローラーは
params[:id]ではなくparams[:slug]を受け取ります - 例:
/products/123ではなく/products/vintage-leather-jacket - SEO に適した URL や、数値以外の識別子を使う場合に便利です
9. デフォルトオプション
リソースのデフォルトオプションを設定します。
resources :categories, defaults: { subcategory: false }
これらのデフォルト値は params[:subcategory] から利用できます。
10. カスタムルートリゾルバー
ポリモーフィックなパスヘルパー用のカスタムリゾルバーを定義します。
resolve 'Bulk::Accessories' do |form|
form.persisted? ? [form.accessory] : [form.tank, :accessories]
end
resolve 'AssemblyItem' do |item|
[item.host, item]
end
使い方: これにより、url_for(@form_object) や link_to(@assembly_item) が正しく動作します。
11. セッションルート
関連する認証アクションには、scope とともに controller ブロックを使用します。
controller :sessions do
get :login, action: :new
delete :logout, action: :destroy
scope :auth do
get :failure
match 'ADFS/callback', action: :create, via: %i[get post], as: :adfs_callback
end
end
12. 制約付きのエンジンのマウント
認証制約を指定して管理エンジンをマウントします。
# Allow access only if user is logged in and is admin
mount PgHero::Engine, at: :pghero,
constraints: -> env {
env.session[:user_id].present? &&
User.find_by(id: env.session[:user_id])&.admin?
}
# Redirect to login if not authenticated
get :pghero, to: redirect('/login'), anchor: false,
constraints: -> env { env.session[:user_id].blank? }
13. ヘルスチェックルート
# Production health check
mount Health::Check::Engine, at: 'health-check' if Rails.env.production?
# Rails 7.1+ health check
get :up, to: 'rails/health#show', as: :rails_health_check
完全な構成例
以下は、すべてのベストプラクティスに従って整理されたルートファイルの例です。
Rails.application.routes.draw do
# 1. Define concerns first (reusable route patterns)
concern :commentable do
resources :comments, commentable_type: parent_resource.name.classify
end
concern :archivable do
patch :archive, on: :member
patch :unarchive, on: :member
end
concern :searchable do
get :search, on: :collection
end
# 2. Main routes with shallow nesting
scope shallow: true do
# Top-level resources
resources :users, except: %i[show] do
resource :profile, only: %i[show edit update]
resource :settings, only: %i[edit update]
end
resources :products, concerns: %i[commentable archivable searchable] do
resources :reviews, except: %i[index]
resources :variants, except: %i[index show]
end
# Nested resources
resources :projects do
resources :tasks, concerns: %i[commentable] do
resource :assignment, only: %i[create destroy]
end
end
end
# 3. Session/authentication routes
controller :sessions do
get :login, action: :new
post :login, action: :create
delete :logout, action: :destroy
end
# 4. Admin routes with constraints
namespace :admin do
resources :users
resources :settings, only: %i[index update]
end
# 5. Mounted engines (with constraints if needed)
mount Sidekiq::Web, at: '/sidekiq', constraints: AdminConstraint.new
# 6. Custom route resolvers (for polymorphic routing)
resolve 'ProjectTask' do |task|
[task.project, task]
end
# 7. Health checks
get :up, to: 'rails/health#show', as: :rails_health_check
# 8. Root route
root 'dashboard#index'
end
レビューチェックリスト
ルートをレビューまたは生成する際は、次の点を確認してください。
- Concern がファイルの先頭で定義されている
- Concern が DRY で、複数のリソース間で再利用できる
- カスタムパラメーター(
commentable_typeなど)でparent_resource.name.classifyを使用している -
*_typeのデフォルト値を渡す Concern に、resource_forを使用する対応コントローラーがある(polymorphic-parent-resourcesを参照) -
scope shallow: trueで浅いネストが有効になっている - リソースのアクションを制限するために
only:またはexcept:を明示的に使用している - ネストされたリソースがパターンに従っている(多くの場合、index/show はなし)
- 単数リソースで
resourcesではなくresourceを使用している - コレクションルート/メンバールートで
on:パラメーターを使用している - 必要に応じて、カスタムパラメーター名に
param:を使用している - フォームオブジェクトとポリモーフィックモデル用にルートリゾルバーが定義されている
- 管理エンジンに認証制約がある
- ルートが定義されている
- ルートが論理的な順序で整理されている(Concern → リソース → カスタムルート → エンジン → リゾルバー → ルート)
避けるべきアンチパターン
❌ ネストされたリソースのパターンを繰り返さないでください:
resources :articles do
resources :comments, commentable_type: 'Article'
end
resources :posts do
resources :comments, commentable_type: 'Post'
end
✅ 代わりに Concern を使用してください:
concern :commentable do
resources :comments, commentable_type: parent_resource.name.classify
end
resources :articles, concerns: %i[commentable]
resources :posts, concerns: %i[commentable]
❌ shallow を使わずに深くネストしないでください:
resources :companies do
resources :projects do
resources :tasks do
# Results in /companies/:company_id/projects/:project_id/tasks/:id/edit
end
end
end
✅ 浅いネストを使用してください:
scope shallow: true do
resources :companies do
resources :projects do
resources :tasks # edit becomes /tasks/:id/edit
end
end
end
❌ 不要なアクションをすべて残さないでください:
resources :duplications # Provides 7 REST actions but only need create
✅ 明示的に指定してください:
resources :duplications, only: %i[create]
❌ 単数リソースに複数形を使わないでください:
resources :profiles, only: %i[show] # There's only one profile per user
✅ 単数形の resource を使用してください:
resource :profile, only: %i[show]
❌ コンテキストの型をハードコードしないでください:
concern :commentable do
resources :comments, commentable_type: 'Article' # Only works for articles
end
✅ parent_resource を使用してください:
concern :commentable do
resources :comments, commentable_type: parent_resource.name.classify
end
高度なパターン
ネストされた Concern を持つ Concern
再利用性の高いルーティングパターンを実現するため、Concern から他の Concern を参照できます。
concern :searchable do
get :search, on: :collection
get :autocomplete, on: :collection
end
concern :taggable do
resources :tags, only: %i[index create destroy],
concerns: %i[searchable],
taggable_type: parent_resource.name.classify
end
resources :articles, concerns: %i[taggable]
# Articles get tags with search and autocomplete functionality
複数のカスタムパラメーター
Concern に複数のカスタムパラメーターを渡すことができます。
concern :versioned do
resources :versions,
only: %i[index show],
param: :version_number,
shallow: false,
versionable_type: parent_resource.name.classify
end
これらのカスタムパラメーターは、ルーティングメタデータとしてコントローラーから利用できます。
# In controller
def index
@versionable_type = request.path_parameters[:versionable_type] # => "Article"
end
コンテキスト固有のルート追加
concern を適用した後、特定のリソースに追加のルートを追加します:
resources :articles, concerns: %i[commentable] do
# Add article-specific routes beyond the concern
get :preview, on: :member
post :publish, on: :member
end
条件付きエンジンマウント
環境に基づいてエンジンを条件付きでマウントします:
if Rails.env.production?
mount HealthCheck::Engine, at: 'health-check'
end
unless Rails.env.production?
mount LetterOpenerWeb::Engine, at: '/letter_opener'
end
一般的なルーティングパターン
これらのパターンは Rails アプリケーションでよく使われ、concern を使用して実装できます:
コメント可能なリソース:
- パターン:コメントを持つことができるリソース
- 実装:ポリモーフィック関連付けを持つネストされたコメントリソース
- 適用先:記事、ブログ投稿、製品、タスクなど
複製可能なリソース:
- パターン:クローン/複製できるリソース
- 実装:複製アクション用の作成専用ネストリソース
- 適用先:テンプレート、ドキュメント、設定など
アーカイブ可能なリソース:
- パターン:アーカイブ/アーカイブ解除できるリソース
- 実装:アーカイブ状態を変更するメンバールート
- 適用先:プロジェクト、ドキュメント、レコードなど
検索可能なリソース:
- パターン:検索/フィルター機能を持つリソース
- 実装:検索操作用のコレクションルート
- 適用先:製品、ユーザー、記事など
バージョン管理されたリソース:
- パターン:バージョン履歴を持つリソース
- 実装:多くの場合読み取り専用の、ネストされたバージョンリソース
- 適用先:ドキュメント、API リソース、設定など
タグ付け可能なリソース:
- パターン:タグ付け/カテゴリ分けできるリソース
- 実装:作成/削除アクションを持つネストされたタグ
- 適用先:記事、画像、ブックマークなど
AI エージェント向けの使用手順
ルートのレビューを依頼された場合:
- ルートが整理されていることを確認します:concern → リソース → カスタムルート → エンジン → リゾルバー → ルート
- concern が適切に定義され、再利用可能であることを確認します
shallowを使用すべき深いネストがないか確認します- リソースで
only:/except:が適切に使用されていることを確認します - 単数形と複数形のリソースの使い分けを確認します
- concern にすべき重複パターンがないか確認します
- カスタムリゾルバーがモデルの関連付けと一致していることを検証します
新しいルートの生成を依頼された場合:
- 動作が再利用可能か判断します → concern を作成/使用します
- リソースを親の下にネストすべきか確認します
- 明示的に必要な場合を除き、ネストされたリソースには shallow nesting を有効にします
- 必要なアクションに基づいて
only:またはexcept:を指定します - 親ごとに1つだけ存在する場合は
resource(単数形)を使用します - 必要に応じてカスタムのコレクション/メンバールートを追加します
- フォームオブジェクトまたはポリモーフィックモデルの場合はルートリゾルバーを作成します
- 同様の機能に対する既存の concern パターンに従います
ルートの更新を依頼された場合:
- 既存のパターンとの一貫性を保ちます
- 複数のリソースに同様の機能を追加する場合は、リファクタリングして concern を使用します
- コードを重複させず、既存の concern を更新します
- shallow nesting の方針を維持します
- 確立された構成に従ってルートを整理します
- モデルの関連付けが変更された場合は、カスタムリゾルバーを更新します
ルートのテスト
変更後は必ずルートを確認します:
# List all routes
rails routes
# Search for specific routes
rails routes | grep products
# Show routes for a specific controller
rails routes -c products
# Show routes with expanded format
rails routes --expanded
# Filter by HTTP verb
rails routes -g POST
最終更新:2026年2月