コメントを投稿機能の流れと注意点

## はじめに
投稿した内容に対してコメントをつける機能を導入する時のRuby on railsの流れがわかりづらかったので、まとめてみました。
スクール初学生さんも同じところで悩まれる方も多いと思いますので参考にして頂ければなと思います。

## 解決したい内容
投稿内容の詳細ページにコメントをつけるまでの流れを解説

### 前提条件
今回は
投稿したツイートを　prototype
投稿に対するコメントを　comment
とします。

## 全体の流れ
①まず初めにprototypeコントローラーのshowアクションにて@commentに空のインスタンスを生成



```ruby
def show
    @prototype = Prototype.find(params[:id])
    @comment = Comment.new
    @comments = @prototype.comments.includes(:prototype)
  end
```
※ @prototypeは詳細画面を表示する情報があらかじめ入っていってshowのviewファイルに渡されるている。

②@commentsに@prototypeに結びついた全てのコメント情報とそれに結びつくユーザー情報を代入しshowのviewファイルに送る。

```ruby
<main class="main">
  <div class="inner">
    <div class="prototype__wrapper">
      <p class="prototype__hedding">
        <%= @prototype.title %>
      </p>
      <%= link_to @prototype.user.name, root_path, class: :prototype__user %>
      <% if user_signed_in? && current_user.id == @prototype.user_id %>
        <div class="prototype__manage">
          <%= link_to "編集する", edit_prototype_path(@prototype.id), class: :prototype__btn %>
          <%= link_to "削除する", prototype_path(@prototype.id),data: { turbo_method: :delete }, class: :prototype__btn %>
        </div>
      <% end %>
 
      <div class="prototype__image">
        <%= image_tag @prototype.image %>
      </div>
      <div class="prototype__body">
        <div class="prototype__detail">
          <p class="detail__title">キャッチコピー</p>
          <p class="detail__message">
            <%= @prototype.catch_copy %>
          </p>
        </div>
        <div class="prototype__detail">
          <p class="detail__title">コンセプト</p>
          <p class="detail__message">
            <%= @prototype.concept %>
          </p>
        </div>
      </div>
      <div class="prototype__comments">
       
        <%if user_signed_in? %>
            <%= form_with model: [@prototype, @comment],local: true do |f|%> 
            <div class="field">
              <%= f.label :content, "コメント" %><br /> 
              <%= f.text_field :content, id:"comment_content" %>
            </div>
            <div class="actions">
              <%= f.submit "送信する", class: :form__btn  %>
            </div>
            <% end %>
          <% end %>
```

③送られた情報は全て対象のインスタンス変数に代入される

```ruby
<%= form_with model: [@prototype, @comment],local: true do |f|%> 
            <div class="field">
              <%= f.label :content, "コメント" %><br /> 
              <%= f.text_field :content, id:"comment_content" %>
            </div>
            <div class="actions">
              <%= f.submit "送信する", class: :form__btn  %>
            </div>
            <% end %>
```

④このコメントを入れるフォームに情報を入力すると@commentの中は現時点で空なのでコメントコントローラーのcreateアクションにパラメーターとして送られる。

## 注意点

※行き先をform_withのmodel:で定義しているがここで行き先を決めるルーティングを見るとプロトタイプのidが含まれないとcommentコントローラーのcreateアクションにパラメーターが送られない。

なのでmodel: [@prototype, @comment]という書き方をすることでパスにprototypeのidを含んだパラメーターとして送る事ができる。
(つまりはcommentのcreateアクションに飛ぶ事ができる)

```ruby
Prefix 　　　　　　　　　Verb   　　　　　　URI 　　　　　　　　　Pattern            Controller#Action
prototype_comments 　　POST   /prototypes/:prototype_id/comments(.:format)    comments#create
```

```ruby
class CommentsController < ApplicationController

  def create
    @comment = Comment.new(comment_params)
    if @comment.save
      redirect_to prototype_path(@comment.prototype)
    else
      @prototype = @comment.prototype
      @comments = @prototype.comments
      render "prototypes/show"
    end
  end

  private
  def comment_params
    params.require(:comment).permit(:content).merge(user_id: current_user.id, prototype_id: params[:prototype_id])
  end
end
```

⑤送られた先のcreateアクションの処理

まずnewメソッドで送られてきたパラメーターをストロングパラメーターを用い必要なパラメーターが入った情報を@commentに代入する。

保存できた場合は、詳細の@commentが存在しているprototypeのshowページにいく。

(行き先のルートを@comment.prototypeとしているため)

redirect_toを用いているのでまたルーティング、purototypeのshowアクションの順に処理される(つまりは①番の処理に戻る。)

ダメだった場合の処理

@prototypeに@commentが存在しているprototypeの情報(レコード)のみを代入する。

( @prototype = @comment.prototype　の意味)

次に@commentsに@prototypeに結びついている全てのcommentsを取得し代入する。

(  @comments = @prototype.comments　の意味)

(ここで単数複数系が違うのはアソシエーションの定義に準ずるため)

その二つのインスタンス変数を定義したものをprototypeのviewファイルに渡す。

#### なぜインスタンス変数@prototypeと@commentsを定義しているのか？

prototypeのshowアクション①番の処理でも同じように、この２つを変数を定義しているが、renderだとviewファイルにそのまま戻るので、戻るときに@を使わないと情報を渡せないためここでも行き先のviewファイルに渡すインスタンス変数@を定義する必要がある。

ダメだった場合は一つ前のviewファイルにelseで定義したインスタンス変数が送られる。



```ruby
merge(user_id: current_user.id, prototype_id: params[:prototype_id])
```

この部分はcommentテーブルのuser_idカラムに、ログインしているユーザーのid(usersテーブルのログインしているレコードのid)が代入される。

そしてcommentテーブルのprototype_idに、paramsとして送られてきたルーティングのパラメーターprototype_idを代入している。