rails ルーティング

# はじめに
今回は公式ドキュメントをもとにコメントなどを入れながら、railsルーティングをまとめてみたいと思います。

# 基本的な書き方
config/routes.rb はRailsアプリケーションで使用されるルーティングに関する情報を含むファイルです。
このファイルにルートを定義することで、アプリケーションのURLとコントローラーのアクションを関連付けることができます。

基本的なルーティングの書き方は以下のようになります。
```
get '/users/:id', to: 'users#show', as: 'user'
get 'profile', action: :show, controller: 'users'
```
                                                                              

# resourceとresources
先ほど基本的なルーティングの書き方を示しましたが、実はそこまで使う機会は多くありません。
どちらかといえばこれから紹介する方法で書くことが多いので、ぜひそちらの書き方を押さえましょう。

```
resource :user
```
| HTTP verb | パス | コントローラ#アクション | 目的 |
|:-:|:-:|:-:|:-:|
|GET  |/users/new |users#new|ユーザー作成用のHTMLフォームを返す|
|POST |/users |users#create|ユーザーを作成する   |
|GET  |/users/:id |users#show|1つしかないuserリソースを表示する |
|GET  |/users/:id/edit |users#edit|ユーザー編集用のHTMLフォームを返す  |
|PATCH/PUT |/users/:id |users#update|1つしかないuserリソースを更新する|
|DELETE|/users/:id   |users#destroy|userリソースを削除する   |


```
resrouces :users
```
| HTTP verb | パス | コントローラ#アクション | 目的 |
|:-:|:-:|:-:|:-:|
|GET  |/users | users#index| すべてのユーザーの一覧を表示 |
|GET  |/users/new |users#new|ユーザーを1つ作成するためのHTMLフォームを返す|
|POST |/users |users#create|ユーザーを1つ作成する   |
|GET  |/users/:id |users#show|特定のユーザーを表示する   |
|GET  |/users/:id/edit |users#edit|ユーザー編集用のHTMLフォームを1つ返す  |
|PATCH/PUT |/users/:id |users#update|特定のユーザーを更新する   |
|DELETE|/users/:id   |users#destroy|特定のユーザーを削除する   |

これらの大きな違いは２つあります。
１、resourceはindexアクションを作成しない
２、resourceは:idを作成しない

以上から、以下のような使い分けになります。

::: note
複数のリソース=>resources
単一のリソース=>resource
:::

resourceは例えばログインしている場合などがそうですね。
わざわざidを取得する必要がないので、その場合はresourceとなります。

# namespace
namespaceメソッドは、Railsのルーティングシステムで、特定のコントローラーやビューに名前空間を設定するために使用されます。名前空間は、関連するコントローラー、ビュー、およびヘルパーをグループ化することができます。

要は、プレフィックスをつけられるということです。

admin画面などが多い気がしますが、例えば以下のように書くと
resource :usersで作成したroutesの頭にadminがつきます。
```
  namespace :admin do
   resources :users
  end
```

| HTTP verb | パス | コントローラ#アクション | 名前付きルーティングヘルパー |
|:-:|:-:|:-:|:-:|
|GET  |/admint/users | admin/users#index| admin_users_path |
|GET  |/admin/users/new |adming/users#new|new_admin_user|
|POST |/admin/users |admin/users#create|admin_users_path   |
|GET  |/admin/users/:id |admin/users#show|admin_user_path(:id)|
|GET  |/admin/users/:id/edit |admin/users#edit|edit_admin_user_path(:id)|
|PATCH/PUT |/admin/users/:id |admin/users#update|admin_user_path(:id)|
|DELETE|/admin/users/:id |admin/users#destroy|admin_user_path(:id)|

公式ドキュメントは以下のように補足が書かれています。

::: note
例外的に、(/adminが前についていない) /articlesをAdmin::ArticlesControllerにルーティングしたい場合は、以下のようにすることもできます。
```
scope module: 'admin' do
  resources :articles, :comments
end
```
以下のようにブロックを使わない記述も可能です。

```
resources :articles, module: 'admin'
```
逆に、/admin/articlesを (Admin::なしの) ArticlesControllerにルーティングしたい場合は、以下のようにscopeブロックでパスを指定できます。

```
scope '/admin' do
  resources :articles, :comments
end
```
以下のように単数形ルーティングでもできます。
```
resources :articles, path: '/admin/articles'
```
:::


# ルーティングのネスト
ルーティングはこれまでのような書き方だと対応できない場合が出てきます。
例えば、「書籍にコメントをする」みたいな機能がある場合、様々な書籍に様々なコメントがあるわけです。

「ある本のあるコメントを表示したいな」と考えた時には、これまでのルーティングでは対応できません。そんな時にルーティングをネストさせる必要があります。
```
resources :books do
  resources :comments
end
```

このように書いた場合、以下のようにルーティングが生成されます。
```
Prefix         Verb    URI Pattern                            Controller#Action
book_comments GET     /books/:book_id/comments(.:format)     comments#index
              POST    /books/:book_id/comments(.:format)     comments#create
new_book_comment GET /books/:book_id/comments/new(.:format) comments#new
edit_book_comment GET /books/:book_id/comments/:id/edit(.:format) comments#edit
book_comment GET     /books/:book_id/comments/:id(.:format) comments#show
              PATCH   /books/:book_id/comments/:id(.:format) comments#update
              PUT     /books/:book_id/comments/:id(.:format) comments#update
              DELETE  /books/:book_id/comments/:id(.:format) comments#destroy
```

このように生成すると、例えば書籍とコメントのどちらもidがついているので、
それぞれのidを指定することで、特定の書籍に対する特定のコメントを表示できるわけですね。
```
/books/:book_id/comments/:id
```

ただし、注意点としてネストさせると複雑になるため、多くても1回が良いです。
それ以上する場合は、index/new/createのようなidを持たないもの（コレクション）のアクションだけを親のスコープの下で生成するという手法があります。

```
resources :books do
  resources :comments, only: [:index, :new, :create]
end
resources :comments, only: [:show, :edit, :update, :destroy]
```

これは、shallowオプションを書くことで浅いネストを実現できます。（結果は上と同じです。）
```
resources :articles do
  resources :comments, shallow: true
end
```

また、shallowをブロックで書くこともできます。
```
shallow do
  resources :books do
    resources :comments
    resources :quotes
    resources :drafts
  end
end
```

どのような出力をしたいのかに応じて使い分けていきましょう。

# ルーティングのconcern機能
concernを使うことで、他のリソースやルーティング内で使い回せる共通のルーティングを宣言できます。
これは、まあ使っても使わなくてもいい気がします。こんなものもあるんだなという認識で良いと思います。

```
concern :commentable do
  resources :comments
end

concern :image_attachable do
  resources :images, only: :index
end
```

concernを利用すると、同じようなルーティングを繰り返し記述せずに済み、
複数のルーティング間で同じ振る舞いを共有できます。
```
resources :messages, concerns: :commentable

resources :articles, concerns: [:commentable, :image_attachable]
```

上のコードは以下と同等です。（個人的にはこっちの方がわかりやすい、、、）
```
resources :messages do
  resources :comments
end

resources :articles do
  resources :comments
  resources :images, only: :index
end
```
複数形のconcerns呼び出しはルーティング内のどの場所にでも配置できます。scopeやnamespaceブロックでは以下のように利用できます。
```
namespace :articles do
  concerns :commentable
end
```

# memberとcollection
他にもルーティングをさらにカスタマイズしたい場合にmemberやcollectionがあります。
どちらも似たような使い方ですが、idを付与するかどうかに大きな違いがあります。

結論から伝えると以下の通りです。

:::note
member=>idを付与する
collection=>idを付与しない
:::

まあ名前の通り、memberは1人、2人のようなイメージなのでidがつくという感じですかね。

## member

```
resources :users do
  member do
    get 'hoge'
  end
end
```
上記のように member を使用すると以下のようにルーティングが設定されます。
/usersにidとhogeが乗っている（on）感じですね。
```
/users/:id/hoge
```

アクションが１つだけの場合は、以下のように書きます。
```
resources :users do
  get 'hoge', on: :member
end
```
## collection
```
resources :users do
  collection do
    get 'hoge'
  end
end
```
上記のようにcollection を使用すると以下のようなルーティングが設定されます。
/usersにhogeが乗っている（on）感じですね。
```
/users/hoge
```
こちらもアクションが１つだけの場合は、以下のように書きます。
```
resources :users do
  get 'hoge', on: :collection
end
```

７つのルーティングやネストだと対応できないなとなった時に使用を検討してみましょう。

# 名前付きルーティング :as

:asオプションを使うと、任意のルーティングに名前を指定できます。
名前付きルーティングを使用すると、以下のようなメリットがあります。
* コードの可読性が向上する
* URLの変更にも柔軟に対応できる

例えば、以下のようなルーティングがあるとします。

```
get '/books/:id', to: 'books#show'
```
このルーティングは、/books/:id というURLにGETリクエストが送信された場合、BooksControllerの showアクションが呼び出されます。

名前付きルーティングを使用すると、以下のように書くことができます。
```
get '/books/:id', to: 'books#show', as: :book
```
このルーティングでは、:book という名前が付けられています。

これにより、ルートを参照するための短いエイリアスが作成されます。
例えば、ビューから book_path(@book) というメソッドを呼び出すことで、/books/:id というURLにアクセスできます。

ルートが複雑である場合や、複数のビューやコントローラーで同じルートを参照する場合は、名前付きルートを積極的に使用することをおすすめします。

# 既存のルーティングを表示する

## --expanded
--expandedオプションを使うと以下のように表示できるらしい。めっちゃ見やすい...
でもrailsのバージョンによっては使用できないみたいです...(少なくともRails 5.2.3では使用できませんでした。)
```
--[ Route 1 ]----------------------------------------------------
Prefix            | users
Verb              | GET
URI               | /users(.:format)
Controller#Action | users#index
--[ Route 2 ]----------------------------------------------------
Prefix            |
Verb              | POST
URI               | /users(.:format)
Controller#Action | users#create
```

## -g
これはgrepオプションですね。多くの人が使っていると思います。
以下を実行するとURLヘルパー名、HTTP verb、URLパスのいずれかに部分マッチするルーティングが出力されます。
```
rails routes -g users
```
以下のようにもかけますが、-gの方がいいですね。
```
rails routes | grep users
```

## -c
特定のコントローラに対応するルーティングだけを表示したい場合は、-cオプションを使います。

-gオプションだと、URLヘルパー名、HTTP verb、URLパスのいずれかに部分マッチするルーティングを出力するので、controllerに含まれているルーティングだけ知りたい場合は-cをつけると良いです。

# まとめ
以上がrailsルーティングのまとめになります。
個人的にあんまり使わないなという部分は飛ばしたりしているので、より詳しく知りたい方は公式ドキュメントを参照してみると良いと思います。

https://railsguides.jp/routing.html