【Rails】Twitterクローンを作ってみた 〜コメント機能の作成〜

## はじめに
[【Rails】Twitterクローンを作ってみた 〜ツイート機能編〜](https://qiita.com/bloom__fu/items/975432a9aae39dae958f)の続きです。こちらを前提に進めていきますので、まだご覧になっていない方はそちらからご覧ください！※こちらはdockerでの環境構築を省きます。
## サービス環境
- ruby 3.0.0
- Rails 6.0.4
- docker
- mysql 8.0.2
- Slim, SCSS

## コメント機能作成
#### 条件
- TweetをクリックでそのTweetのコメントが見られる（コメントページ）
- コメントページの「コメント」をクリックでコメント新規作成に遷移できる
- コメントを投稿するとコメントページにリダイレクト
コメントモデルの作成し、Userモデル, Tweetモデルとコメントを関連付けさせてください。コメントもTweet同様140文字までとします。また、コメントモデルのテキスト部分のカラム名はtextとしてください。
#### 実装流れ(簡略)
① Userモデル、Tweetモデルに紐付けたCommentモデル作成(textカラムを持つ)
② db:migrate
③ userモデル編集(has_many :comments, dependent: :destroy)
④ tweetモデル編集(userモデル同様)
⑤ commentモデル編集(バリデーションをかけてtextを最大140文字までとする)
⑥ commentsコントローラ作成、編集
⑦ tweetsコントローラ編集(showアクション)
⑧ routes.rb追記(ネスト)
⑨ comments/new.html.slim書く。cssも同様に。 ←難
⑩ tweets/show.html.slim書く。cssも同様に。
#### ツイート詳細ページ
![スクリーンショット 2022-11-13 17.38.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1961802/a64985ea-317e-e5d1-1f7f-7316b48103a0.png)

#### コメントページ
![スクリーンショット 2022-11-13 17.41.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1961802/f2960f8d-b04b-8f6e-364a-e7636e688c1d.png)

#### ツイート詳細ページ(コメント後)
![スクリーンショット 2022-11-13 17.42.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1961802/07ce8e39-47f3-0821-9722-87d21597c9e2.png)



## 解説
#### views/comments/new.html.slim
```slim
h4 コメントを投稿する
= form_with model: @comment, url: tweet_comments_path, local: true do |f|
  = f.hidden_field :tweet_id, :value => @tweet_id
  .c-group 
    = f.label :text
    = f.text_area :text, maxlength: 140, placeholder: 'コメントを記入してみよう！', class: "form-control", required: 'required'
  .btn-space  
    = f.submit nil, class: 'btn'
  .actions
    = link_to '戻る', root_path, class: 'cancel-button'
```
こちらはかなり苦戦しました。前回セクションのツイート機能作成の通りにhtmlを書けば良いのかと思っていたら、落とし穴でした。まずform_withタグで指定するモデルはcommentモデルです。モデルを指定しない場合、commentsコントローラでparamsを受け取れません。さらにurlでpathを渡します。urlを渡さない場合、モデルがurlを自動推測しますが、ここでは自動推測してくれません。
```slim
= f.hidden_field :tweet_id, :value => @tweet_id
```
こちらはcommentモデルがtweet_idというパラメーターに渡したいインスタンス(@tweet_id)を指定して、次のアクションに渡したい時に使用します。よって次のアクション(コメントの投稿)をした際のパラメーターをコンソールで見てみると以下のようになります。
```
Parameters: {"authenticity_token"=>"〜〜〜", "comment"=>{"tweet_id"=>"数字", "text"=>"私も苦戦しました。"}, "commit"=>"登録する", "tweet_id"=>"数字"}
```


#### comments_controller.rb
```ruby
class CommentsController < ApplicationController
  before_action :find_tweet_id

  def new
    @comment = Comment.new
  end

  def create
    @comment = current_user.comments.build(comment_params)
    if @comment.save
      redirect_to tweet_path(@tweet_id), notice: "コメントを投稿しました。"
    else
      redirect_to new_tweet_comment_path(@tweet_id), alert: "コメントの投稿に失敗しました。"
    end
  end

  private

  def find_tweet_id
    @tweet_id = params[:tweet_id]
  end

  def comment_params
    params.require(:comment).permit(:tweet_id, :text)
  end
end
```
ここで肝となるのが一番最初のコードです。
```ruby
before_action :find_tweet_id
```
ここで最初にパラメーターとして[:tweet_id]を受け取らないとcreateアクションでcommentがtweet_idを見つけられず、常にコメントの投稿に失敗し続けます。失敗している状態で、先程の```hidden_field```で作り上げたパラメーターを見てみましょう！
```
Parameters: {"authenticity_token"=>"〜〜〜", "comment"=>{"tweet_id"=>"", "text"=>"私も苦戦しました。"}, "commit"=>"登録する", "tweet_id"=>"数字"}
```
commentのtweet_idが空になっていますよね。注意しましょう！

## 実装を通して学んだこと
#### 1. form_withタグのmodel指定とurl指定
今まではmodel指定のみであったが、今回はurl指定も必要なことを学びました。commentは２つのモデルと紐づいており、自動的に推測してくれないと判明した際はurl等の指定も同時にしてあげなければならないことを学びました！
#### 2. hidden_fieldタグ
このタグによって次のアクションに渡したいパラメーターやインスタンスを指定することができるということを学びました。今回のコメント機能は常にツイートに紐付いているため、ツイートのidを常に考慮しなければなりませんでした。
#### 3. ルーティングのネスト
```ruby
resources :tweets do
  resources :comments
end
```
tweetモデルに紐づくcommentモデルのルーティングは上記のように書けます。


## 感想
今回はかなりつまづきました。htmlでのform_withタグではurl指定をしておらず永遠にエラーが出る状況が続きました笑
hidden_fieldタグを調べながら書き、tweet_idをパラメーターで渡せる状況にしたものの、commentsコントローラではbefore_actionとしてtweet_idを渡しておらずパラメーターのtweet_idが空で渡されてしまっており、何度もエラーを出しました。。
エラーを出し、調べて試してみてうまく動くという経験はかなり大事なものだと感じました。今後こういったエラーが出てもすんなり対応できると思います！
次回は**画像アップロード機能の作成**についてアウトプットしていこうと思います！読んでいただきありがとうございました。
## 参考記事
- https://techracho.bpsinc.jp/hachi8833/2022_01_06/39502
- https://sakurawi.hateblo.jp/entry/hidden_field