mcpField
R
routing-patterns

routing-patterns

github.com/rolemodel開発746 回インストール3 日前に更新
リポジトリ

routing-patterns について

routing-patternsは、AIエージェントがRailsのルートをレビュー、生成、更新するためのスキルです。再利用可能なconcernや浅いネストなど、保守しやすいルート構成を扱います。

主な機能

  1. 01再利用可能なルートconcern
  2. 02浅いネストのルート
  3. 03アクションの明示的な制限
  4. 04ネスト・単数リソース
  5. 05カスタムパラメーターとリゾルバー
  6. 06制約に基づくルーティング

活用シーン

  1. 01Railsのルートファイルのレビュー
  2. 02再利用可能なリソースルートの生成
  3. 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_rails gem(>= 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 エージェント向けの使用手順

ルートのレビューを依頼された場合:

  1. ルートが整理されていることを確認します:concern → リソース → カスタムルート → エンジン → リゾルバー → ルート
  2. concern が適切に定義され、再利用可能であることを確認します
  3. shallow を使用すべき深いネストがないか確認します
  4. リソースで only:/except: が適切に使用されていることを確認します
  5. 単数形と複数形のリソースの使い分けを確認します
  6. concern にすべき重複パターンがないか確認します
  7. カスタムリゾルバーがモデルの関連付けと一致していることを検証します

新しいルートの生成を依頼された場合:

  1. 動作が再利用可能か判断します → concern を作成/使用します
  2. リソースを親の下にネストすべきか確認します
  3. 明示的に必要な場合を除き、ネストされたリソースには shallow nesting を有効にします
  4. 必要なアクションに基づいて only: または except: を指定します
  5. 親ごとに1つだけ存在する場合は resource(単数形)を使用します
  6. 必要に応じてカスタムのコレクション/メンバールートを追加します
  7. フォームオブジェクトまたはポリモーフィックモデルの場合はルートリゾルバーを作成します
  8. 同様の機能に対する既存の concern パターンに従います

ルートの更新を依頼された場合:

  1. 既存のパターンとの一貫性を保ちます
  2. 複数のリソースに同様の機能を追加する場合は、リファクタリングして concern を使用します
  3. コードを重複させず、既存の concern を更新します
  4. shallow nesting の方針を維持します
  5. 確立された構成に従ってルートを整理します
  6. モデルの関連付けが変更された場合は、カスタムリゾルバーを更新します

ルートのテスト

変更後は必ずルートを確認します:

# 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月

コメント