Railsのルーティングまとめ


## 背景・目的
* Railsのルーティングにおけるパス名（users_pathなど）の生成規則と複数形・単数形の違いについて
理解が曖昧なので、Railsガイドを参考に理解を深める
* これまで自分が見たコードを踏まえて頻出そうなものを、自分用に以下にまとめる
* Railsガイドの写経なので本家を見た方が絶対に良い


## 明示的なルーティング指定
```ruby
# '/hoges/:id'でhogesコントローラのshowアクションにルーティング
get '/hoges/:id', to: 'hoges#show'

# 'fuga'でhogesコントローラのindexアクションにルーティング
get '/hoges', to: 'hoges#index', as 'fuga'

# '/profile'でusersコントローラのindexアクションにルーティング
get 'profile', to: :index, controller: 'users'
```

## リソースベースのルーティング
* 複数形リソース指定

```ruby
resources :resource_name
```

| HTTP動詞 | パス | コントローラ#アクション | 目的 |
| :---: | :---: | :---: | :---: |
| GET | /resource_name | resource_name#index | リソースの一覧を表示 |
| GET | /resource_name/new | resource_name#new | リソースを1つ作成するためのHTMLフォームを返す | 
| POST | /resource_name | resource_name#create | リソースを1つ作成する | 
| GET | /resource_name/:id | resource_name#show | 特定のリソースを表示する（params[:id]）|
| GET | /resource_name/:id/edit | resource_name#edit | リソース編集用のHTMLフォームを返す |
| PATCH/PUT | /resource_name/:id | resource_name#update | 特定のリソースを更新する |
| DELETE | /resource_name/:id | resource_name#destroy | 特定のリソースを削除する |

* 単数形リソース指定

```ruby
# resource_name#indexへのルーティングが作成されない
resource :resource_name
```

| HTTP動詞 | パス | コントローラ#アクション | 目的 |
| :---: | :---: | :---: | :---: |
| GET | /resource_name/new | resource_name#new | リソースを作成するためのHTMLフォームを返す | 
| POST | /resource_name | resource_name#create | リソースを作成する | 
| GET | /resource_name | resource_name#show | リソースを表示する|
| GET | /resource_name/edit | resource_name#edit | リソース編集用のHTMLフォームを返す |
| PATCH/PUT | /resource_name | resource_name#update | リソースを更新する |
| DELETE | /resource_name | resource_name#destroy | リソースを削除する |

* _pathヘルパーと_urlヘルパー

```ruby
resources :users # リソース名が複数形
resources :student # リソース名が単数形
```
  * リソースが単数形の場合と複数形の場合でindexアクションのパス名が異なる

| コントローラ#アクション | _pathヘルパー | _urlヘルパー |
| :---: | :---: | :---: |
| users#index | **users_path** | **users_url** |
| users#new | new_user_path | new_user_url |
| users#edit | edit_user_path | edit_user_url |
| users#show | user_path | user_url |
| student#index | **student_index_path** | **student_index_url** |
| student#new | new_student_path | new_student_url |
| student#edit | edit_student_path | edit_student_url |
| student#show | student_path | student_url |

* 名前空間とルーティング

  * `app/controller/admin/`配下のpostsコントローラにルーティングする
  
```ruby
namespace :admin do
  resources :posts
end
```

| HTTP動詞 | パス | コントローラ | 名前付きヘルパー |
| :---: | :---: | :---: | :---: |
| GET | /admin/posts | admin/posts#index | admin_posts_path |
| GET | /admin/posts/new | admin/posts#new | new_admin_post_path |
| GET | /admin/posts/:id | admin/posts#show | admin_post_path(:id) |
| GET | /admin/posts/:id/edit | admin/posts#edit | edit_admin_post_path(:id) |


  * `app/controller/admin/`配下のpostsコントローラに`/posts`パスをルーティングする
  
```ruby
scope module: 'admin' do
  resources :posts
end

# 上と同義
resources :posts, module: 'admin'  
```

  * `admin/posts`パスを`(Admin::なしの)PostsController`にルーティングする

```ruby
scope '/admin' do
  resources :posts
end

# 上と同義
resources :posts, path: '/admin/posts'
```

  * ネストしたリソース

```ruby
class Magazine < ActiveRecord::Base
  has_many :ads
end

class Ad < ActiveRecord::Base
  belongs_to :magazine
end  
  
resources :magazines do
  resources :ads
end
```

| HTTP動詞 | パス | コントローラ | 目的 |
| :---: | :---: | :---: | :---: |
| GET | /magazines/:magazine_id/ads | ads#index | 特定の雑誌1冊に含まれる広告を一覧表示する |
| GET | /magazines/:magazine_id/ads/new | ads#new | 特定の雑誌用の広告を作成するHTMLフォームを1つ返す |
| POST | /magazines/:magazine_id/ads | ads#create | 特定の雑誌用の広告を1つ作成する |
| GET | /magazines/:magazine_id/ads/:id | ads#show | ある雑誌に含まれる特定の広告を表示する |
| GET | /magazines/:magazine_id/ads/:id/edit | ads#edit | ある雑誌に含まれる特定の広告を編集するHTMLフォームを一つ返す |
| PATCH/PUT | /magazines/:magazine_id/ads/:id | ads#update | ある雑誌に含まれる特定の広告を更新する |
| DELETE | /magazines/:magazine_id/ads/:id | ads#destroy | ある雑誌に含まれる特定の広告を削除する |

  * 特定のアクションのみを利用するネスト
  
```ruby
resources :posts do
  resources :comments, only: [:index, :new, :create]
end
resources :comments, only: [:show, :edit, :update, :destroy]

# 上と同じ
resources :posts do
  resources :comments, shallow: true
end

# 上と同じ
resources :posts, shallow: true do
  resources :comments
  (resources :quotes)
  (resources :drafts)
end

# 上と同じ
shallow do
  resources :posts do
    resources :comments
    (resources :quotes)
    (resources :drafts)
  end
end  
```

## パスの生成

* オブジェクトからパスとURLを生成

```ruby
resources :magazines do
  resources :ads
end

# usage
magazine_ad_path(@magazine, @ad)
url_for([@magazine, @ad])  
<%= link_to 'Ad details', [@magazine, @ad] %> # 各インスタンスのクラスからパスを判定
<%= link_to 'Edit Ad', [:edit, @magazine, @ad] %>
```


## RESTfulなアクションの追加

* メンバールーティングを追加する

```ruby
resources :photos do
  member do
    get 'preview' # => /photos/:id/preview => photos#preview
  end
end

# 上と同義
resources :photos do
  get 'preview', on: :member
end
```

* コレクションルーティングを追加する

```ruby
resources :photos do
  collection do
    get 'search'
  end
end

# 上と同義
resources :photos do
  get 'search', on: :collection
end
```

## デフォルト定義

* root

```ruby
root to: 'pages#main'
root 'pages#main' # 上の省略形
get '/', to: 'pages#main' # 冗長形

# 名前空間やスコープの内側にrootを置くこともできる
namespace :admin do
  root 'admin#index'
end
root 'home#index'  
```
    

## 参考
Railsガイド　ルーティング：　https://railsguides.jp/routing.html