【フリマアプリ】商品詳細ページのコメント機能（第２回）〜ルーティング編〜


　某スクールにおいて、チーム開発で、フリーマーケットアプリを作成中であり、使用した技術について公開しています。
※初学者のため、ミスや認識違いが多々あると思いますがご了承ください。

# 商品詳細ページにコメント機能を実装しました。
全部で7回に分けて記事を投稿しています。

    |内容             |                  url   |
|:-----------------|------------------:|:-----------------------------:|
| 第１回             |       モデル、マイグレーション編 |    https://qiita.com/sho_U/items/03108801146e65d58413   |
| 第２回         |           ルーティング編 |     https://qiita.com/sho_U/items/5c829b3060be2cce919a |
| 第３回|コントローラー編|https://qiita.com/sho_U/items/8528f336cf0d470cd719|
|第４.1回|ヴュー編(一覧表示）|https://qiita.com/sho_U/items/6190562270c722956547|
|第４.2回|ヴュー編(インプットフォーム）|https://qiita.com/sho_U/items/67c2ede4fc6c605283e2|
|第５回|jquery編|https://qiita.com/sho_U/items/d72b60114f76380d05f6|
|第6回|ajax編|https://qiita.com/sho_U/items/caed9b1471e63d43dd3a|

〜コード全文〜https://qiita.com/sho_U/items/310ac5b653bdfcb99a2c

#ルーティングについて

##必要なルーティングについて
ルーティングを作成するにあたり、遷移先、つまりコントローラーのアクションはどういった物が必要そうか検討しました。

1.**comments#create(createアクション）**

　投稿フォームから、コメントを送信するためのアクション
※ちなみに、商品詳細ページが、コメント投稿画面を兼ねており、（item#showで @comment = Comment.new　を定義しているためnewアクションは不要。@comment = Comment.newを定義する理由は、空の@commentを作成し、form_withの遷移先を自動で判別させるため）

2.**comments#update(updateアクション）**

  コメントを仮削除するためのアクション。なぜ、**削除**なのに**create**なのかといいますと、本アプリは仕様上、１回目のコメント削除は、**仮削除**と言う形で、削除せずデーターベースに保存しておき、復元できるようにしています。よって、本来の意味は削除ではなく、**仮削除状態へ更新する**という動作になります。（ビュー上は、以下のように表示するようにしています。）
<img width="699" alt="ea35e3c4df00a10ac38a3bf51ee10280.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547556/484c0323-5548-37ff-0922-c88d975cf342.png">

3.**comment#restore(restoreアクション）**
 仮削除したコメントを復元させるためのアクション。

4.**comment#destroy(destroyアクション)**
仮削除したコメントを完全に削除するためのアクション。

以上の４つのアクションに遷移するための、ルーティングを作成する必要がありそうです。

##update,destroyに対するルーティング

では、必要なルーティングが洗い出せたところで、それぞれどのように記載するか検討します。
resotore以外の、create,destroy,updataは、Railsで基本となる7つのアクションに含まれるため、まずはそちらから検討します。
シンプルにresouresで作成した場合のルーティングは以下の通りです。

```ruby:routes.rb
resources :comments, only:[:create,:update,:destroy]
```
作成されるルーティング
<img width="1273" alt="272ad84a38eaaf7d7f3f02a8f3acda0d.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547556/9f5cae0c-ab51-15e3-ab3c-dd883d47742c.png">
<img width="1129" alt="a58b7f023fb68dbaf23d6cff0f8ebb61.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547556/2ebaa708-0255-ef9b-82e3-d5f831622074.png">

resourcesから生成されたルーティングで、対応可能か検討します。
ルーティングを作成する上で、考慮しなければいけない事は、コントローラーの各アクションへ遷移する際にpathからparamsとしてデーターを送信する必要があるか、ということです。

上記の、pathを比較するとcreate以外は、末尾に/:idが付与されているのがわかると思います。例えば、updateアクションは、”/commnets/:id"となっており、実際のURLは、　"（略）/commnets/5"　のように:idの部分に、文字列が記載されます。

　この場合は、アクションに対し、paramsというハッシュに、キーはid,バリューは"5"を格納し、

```
params = {id: "5"}
```

という形式で送信されます。

受け取ったアクションでは、

```
pramas[:id] 
=> "5"
```

で、送られてきたバリューを取得することができます。

では、なぜこのような値の受け渡しが必要なのでしょうか。

「create」と、「update,destroy」の両者の違いは、createは**無からコメントを作成する**のに対し、update,destroyは、**現に存在するコメントに対して、行うアクション**であるということです。
　言い換えると、アクションを行う対象のコメントを特定するための、何らかの情報が必要ということです。この役割を、pathに記載された:idの部分が担うわけです。


paramsを使用しなければ、例えばビュー画面で
<img width="641" alt="59519a948d6e9bdbd44ffa0dfa399d34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547556/9c0d5999-b0a0-b8bb-4252-d13a8eee297b.png">
このような、入力フォームを設ける事によって、強引に情報を送ってしまう事は可能であるとは思います。が、ユーザービリティは格段に落ちると思います。

しかし、例えば削除ボタンのlinkタグを以下のように記載すると（@commentには、id:5のコメントのインスタンスが格納されているとします）

```ruby
= link_to '削除する', "/comments/#{@comment.id}" ,method: :patch

# わかりやすさのためprefixは使用していません。
```
リンクボタンをクリックした段階で、自動的に対象コメントのidである　”５”　がコントローラーに送信されるわけです。
こっちの方が、ユーザーにとっても親切です。

ということで、update,destroyについてはresouresによって作成されるルーティングを使用することで実装できそうです。

## createに対するルーティング
では、次にcreateに対するルーティングについて検討したいと思います。

createは先ほども説明した通り、対象となるコメントは必要ありません。
では、上記のように、" /comments "というpathで良いでしょうか？

ここで、第１回の記事を振り返ります。
https://qiita.com/sho_U/items/03108801146e65d58413

```ruby:
class CreateComments < ActiveRecord::Migration[5.0]
  def change
    create_table :comments do |t|
      t.references :item, null: false, foreign_key: true
      t.references :user, null: false, foreign_key: true
      t.integer :delete_check,default: 0
      t.string :comment
      t.timestamps
    end
  end
end
```
Commentモデルのマイグレーションは上記のようになっていました。
これを、データーベース上で表すと
<img width="1037" alt="5bf6ad956ad40fad5ea7464455040d66.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547556/8d278772-bc95-1a8a-a9e0-dc4d474ba399.png">
このようなレコード構造となります。
これらの、カラムのうち「id」　「created_at」　「updated_at」　については、コメント作成時に自動で作成されて格納されます。
「delete_check」については、コメント作成時は、"0"が格納されるようにマイグレーションに定義しています。

「usrer_id」　は、コメント作成者のidが格納されるのですが、これは、コントローラー側で、deviseの機能により現在のログインユーザーのidを格納することが可能です。（コントローラー編で説明）

「comment」（注：commentsテーブルのcommentカラムという意味です。ややこしくてすみません）については、フォームに入力された内容がparamsとして、コントローラーのcreateアクションに受け渡されます。

残る「item_id」カラム、これはコメントと商品を結び付けて、どの商品に対するコメントなのかを特定するためののカラムなのですが、フォームには、コメント内容しか入力する欄がありません。そこで、何とかして、item_idをコントローラーにparamsとして送り届ける必要があります。

つまり、createはupdate,destroyと違い、**どのコメントに対してか**という情報は必要ありませんが、代わりに、**どの商品に対してか**とう情報をコントローラーに送る必要があるのですね。

update,destroyと同じように、pathに情報を組み込んで、送るという手法を用いようとしたら現在の

```
 /comments
```

では不可能ですね。
そこでpathに**:id**  が付与されるように、ルーティングの記載を変える必要があります。

そこで、ルーティングのネストという手法を用います。

今itemsコントローラーに対するルーティングが以下のように記載されているとします。

```ruby:routes.rb
resources :items 
```
このルーティングに対し、入れ子構造でcommentのルーティングを記載します。

```ruby:routes.rb
resources :items do
  resources :comments,only[:create]
end
```
すると、以下のようなpathが生成されます。

```
/items/:item_id/comments
```
これで、 :item_id のところにitemのid情報を埋め込むことにより、params = {item_id: "値" }　というハッシュで対象商品を特定するための情報を送れそうです。

これに、update,destroyを加えて

```ruby:routes.rb
resources :items do
  resources :comments,only: [:create,:update,:destroy]
end
```

以下が生成されたルーティングです。
<img width="1124" alt="efecf4cacf4918dc65cad861d997d67c.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547556/41a70195-e5d5-07b7-e1b4-f87581acbf5a.png">

このように記載することにより、目的は達成されそうです。、、、といいたいところですが、今回は別の方法を採用することにしました。
見てもらったらわかる通り、update,destroyに遷移するためのpathが不必要に長くなっているんですね。この２つは、**どのコメントかを特定**すればいいだけなので、さらにそのコメントが**どの商品に対するものかという情報（/items/:item_id/の部分）**は不要です。無駄に冗長的にすることで、バグの発生リスクや、見通しが悪くなる可能性が生じます。commentsのresourcesをネストするものと、ネストしないものに分けるといった方法もありそうですが、結果として今回は、

```ruby:routes.rb
  resources :items do
  resources :comments, only:[:create,:update,:destroy] do
```
という形でネストせずに組みました。当然、先ほど説明したとおり、createに対し生成されるpathは、

```
/comments
```

となりURLに情報を埋め込むことはできなさそうです。
どのようにして、paramsとして、itemのidを送ったのかは、第4.2回の記事で紹介いたします。

## restoreに対するルーティング
では、最後にrestore対するルーティングについて検討したいと思います。
restoreについては、railsの基本アクションではなく、resouresでは作成できないため手動で作成する必要があります。
また、**コメントを復元する動作も**もupdate,destroyと同じく、対象となるコメントを特定する必要があります。
そのため、

```
/comments/:id/restore 
```

というpathを生成する必要があります。そこで、下記のようにcommentsのルーティングにネストさせることにしました。
手動でルーティングを作成するときには、ネストする際に member do で入れ子にすることにより、:idが付与されます。

```ruby:routes.rb
  resources :comments, only:[:create,:update,:destroy] do
    member do
      get 'restore'
    end
  end
```
復元といっても、何かしらデーターを送信するわけではなくデーターベースにある情報を元に表示するだけなので、httpメソッドは**「get」**にしました。

念のため、生成されたpathを確認したところ
<img width="1221" alt="a9c090618a000f9d7909916ced3b712b.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547556/c88adcf6-e751-a80a-152c-8ffc4a898ec2.png">

目的のpathが生成されていました。

ちなみにネストの方法は**member do**の他に**collection do**という方法もあり、後者の場合は、:idが付与されません。

```ruby:routes.rb
  resources :comments, only:[:create,:update,:destroy] do
    collection do
      get 'restore'
    end
  end
```
<img width="1321" alt="6ea327bb289e69ce696d7b448ae2d787.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547556/a551a0e2-b314-08fa-0fad-0005af874b24.png">

### 次回（第３回）は、コントローラー編となります。
https://qiita.com/sho_U/items/8528f336cf0d470cd719