Railsのルーティングをカスタマイズしたときのメモ

#はじめに
私が業務でRailsアプリケーションのルーティングをカスタマイズ・整理したときのメモです。
[Ruby on Rails Guides](https://guides.rubyonrails.org/routing.html)に書いてある中で、これ使うぞと思うものを自分なりにピックアップしました。

最近Railsの開発をしていないので、もっといい方法をご存知の方がいらっしゃったら声を大にして教えていただけると嬉しいです。

#目次
+ 基本形を自動生成しないで定義したいとき
+ 階層構造をもったURLを定義したいとき
+ オリジナルのActionをちょい足ししたいとき
+ 複数のControllerにオリジナルのActionをちょい足ししたいとき

# 基本形を自動生成しないで定義したいとき
CRUD全てを定義したいときは以下のように書けばよいです。
自動生成しても同じ内容がroutes.rbに定義されます。

```rb
resources :book_shops
```

とはいえ、手動でルーティングを定義するときというのは、特定のActionへのルーティングだけを定義したいときだと思います。例えば、indexとshowしか使わないとか。そんな時は`only: [:許可するアクション]`と書けばOKです。

```rb
resources :book_shops, only: [:index, :show]
# 以下のように定義してもよいですが、面倒だと思います。
# get 'books', to 'books#index'
# get 'books/:id', to 'books#show'
```


# 階層構造をもったURLを定義したいとき
has-manyなどリレーションのあるModelについて実装をするときに起こりうると思います。
例えば、`/book_shop/28/books`にアクセスさせて、IDが28番である本屋の蔵書一覧がわかるとか。

```rb
resources :book_shops do
  resources : books
end
```
> @scivola さんよりご指摘いただき、以下の表の内容を修正いたしました。

| HTTP methods | Path | Controller#Action |
|:-:|:-:|:-:|
| GET | book_shops/:book_shop_id/books | book_shop#index |
| GET | book_shops/:book_shop_id/books/new | book_shop#new |
| POST | book_shops/:book_shop_id/books | book_shop#create |
| GET | book_shops/:book_shop_id/books/:id | book_shop#show |
| GET | book_shops/:book_shop_id/books/:id/edit | book_shop#edit |
| PUT/PATCH | book_shops/:book_shop_id/books/:id | book_shop#update |
| DELETE | book_shops/:book_shop_id/books/:id | book_shop#destroy |

ネストさせる場合も、特定のActionへのルーティングのみ定義することができます。
後ろに`only: [:許可するアクション]`と書けばOKです。

```rb
resources :book_shops do
  resources : books, only: [:index, :show]
end
```

# オリジナルのActionをちょい足ししたいとき

##`/controller/:id/action`形式
例えば、指定した書籍をダウンロードするActionへのルーティングを定義するには、以下のように定義します。

```rb
resources :books do
  member do
    post 'download'
# post 'download', on: :memberでもOK
do
```

基本形に同じく`post 'books/:id/download', to 'book#download'`と任意の場所に定義してもよいですが、私は推奨しません。
同じControllerに対するルーティングは1か所に書いたほうがメンテナンスしやすいからです。バラバラの場所に書くと、何が定義されていて何が定義されていないのか管理するのが大変になります。

##`/controller/action`形式
例えば、書籍の一覧に対して検索をするActionへのルーティングを定義するには、以下のように定義します。

```rb
resources :books do
  collection do
    get 'search'
# get 'search', on: :collectionでもOK
do
```

# 複数のControllerにオリジナルのActionをちょい足ししたいとき
検索用のルーティングを用意したものの、そのActionって色んなところで使うのだけれどもという場合ですね。
ルーティングが一つだとうま味が少ないかと思いますので、以下のActionを追加してみたいと思います。

+ 作成確認画面：`new_confirm`
+ 編集確認画面：`edit_confirm`
+ 削除確認画面：`delete_confirm`

確認画面を足すとかあるあるですよね（たぶん）。
今までの知識でbook_shop_controllerとbook_controllerにルーティングを追加すると以下のようになるはずです。

```rb
resources :book_shops do
  post 'new_confirm', on: :collection
  member do
    post 'edit_confirm'
    post 'delete_confirm'
  end
end

resources :books do
  post 'new_confirm', on: :collection
  member do
    post 'edit_confirm'
    post 'delete_confirm'
  end
end
```
別にこれでもいんですけども、少し冗長ですよね。
今は2つしかないからよいですが、あとから機能追加で数十個もControllerを足すとなれば、routes.rbは地獄絵図と化すでしょう。
`concern`を使えば、上のような冗長さを解決できます。

```rb
resources :book_shops, concerns: :confirmable

resources :books, concerns: :confirmable

concern :confirmable do
  post 'new_confirm', on: :collection
  member do
    post 'edit_confirm'
    post 'delete_confirm'
  end
end
```
最高にイケてるルーティングになったような気がしますね（自画自賛）。

#補足
本当はControllerをサブディレクトリに分ける際のお話もしたかったのですが
ここまででも話が長くなってしまったので割愛させていただきます。

#参考ページ
[Ruby on Rails Guides](https://guides.rubyonrails.org/routing.html)