はじめに
【Rails】Twitterクローンを作ってみた 〜ツイート機能編〜の続きです。こちらを前提に進めていきますので、まだご覧になっていない方はそちらからご覧ください!※こちらは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も同様に。
ツイート詳細ページ
コメントページ
ツイート詳細ページ(コメント後)
解説
views/comments/new.html.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を自動推測しますが、ここでは自動推測してくれません。
= 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
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
ここで肝となるのが一番最初のコードです。
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は2つのモデルと紐づいており、自動的に推測してくれないと判明した際はurl等の指定も同時にしてあげなければならないことを学びました!
2. hidden_fieldタグ
このタグによって次のアクションに渡したいパラメーターやインスタンスを指定することができるということを学びました。今回のコメント機能は常にツイートに紐付いているため、ツイートのidを常に考慮しなければなりませんでした。
3. ルーティングのネスト
resources :tweets do
resources :comments
end
tweetモデルに紐づくcommentモデルのルーティングは上記のように書けます。
感想
今回はかなりつまづきました。htmlでのform_withタグではurl指定をしておらず永遠にエラーが出る状況が続きました笑
hidden_fieldタグを調べながら書き、tweet_idをパラメーターで渡せる状況にしたものの、commentsコントローラではbefore_actionとしてtweet_idを渡しておらずパラメーターのtweet_idが空で渡されてしまっており、何度もエラーを出しました。。
エラーを出し、調べて試してみてうまく動くという経験はかなり大事なものだと感じました。今後こういったエラーが出てもすんなり対応できると思います!
次回は画像アップロード機能の作成についてアウトプットしていこうと思います!読んでいただきありがとうございました。