コロナで無職になった私がエンジニアになるまで

コロナの影響で前職をクビになってから、エンジニアを目指してます。

オリジナルアプリ作成記 5 ~コメント機能の追加~

明けました。今日からまたがんばっていきます。

投稿された依頼ページに一言くらいかけるコメント機能が欲しいなと思ったため
実装してみることにしました。
とりあえずの機能だけ。

モデルの作成

class CreateComments < ActiveRecord::Migration[6.0]
def change
create_table :comments do |t|
t.integer :user_id
t.integer :request_id
t.text :text
t.timestamps
end
end
end

モデルを作成したときに作られるマイグレーションファイルを編集。
ごちゃごちゃしたのはいらないので、とりあえずuser_idとrequest_idは必須。
t.textにはコメントの内容が入る。

 

アソシエーションを組む

request(記事)とuserは複数のcommentを持つことができると考えられる。
=> has_manyで記述。

対してcommentは一つのコメントは一人のuser、requestによるものと考えられる。
=> belongs_toで記述。

このアソシエーションが組めていないと、requestの中に入っているcommentを表示するみたいな記述をしたい時に不便。というかできない。

ルーティング

commentのcreateアクションのルーティングを作成しておく。
このルーティングも少し厄介。
1つの記事のページに表示されるので、ある記事(特定の表示させるrequestのページ)のコメントのようにルーティングさせなければならない。
よって、ネストさせる必要がある。

resources :requests do
resources :comments, only: :create
end

とまぁこんな感じ。
するとrequest_idが含まれたURIがルーティングされる。

  request_comments POST   /requests/:request_id/comments(.:format)                                                 comments#create

コントローラーの作成

commentコントローラーを作成して、createアクションを定義する。

class CommentsController < ApplicationController
def create
comment = Comment.create(comment_params)
redirect_to "/requests/#{comment.request.id}"
end

private
def comment_params
params.require(:comment).permit(:text).merge(user_id: current_user.id, request_id: params[:request_id])
end
end

 

コメントを投稿したら、コメントを投稿したrequestのshowアクションへジャンプするようにする。
でもこのままじゃ空でも投稿されて記録されちゃうので、条件分岐を使用する。

def create
if comment = Comment.create(comment_params)
redirect_to "/requests/#{comment.request.id}"
else
render "/requests/#{comment.request.id}"
end
end

まぁでもそんなに大袈裟なことはしないというか空のメッセージをコメント欄に表示させたくないだけなので、成功しても失敗してもジャンプ先は同じで。

アソシエーションを組んでいるおかげでcommentのコントローラーでもrequest.idと記述しても問題が発生しない。
記述の内容を噛み砕くと、createアクションで作成されたcommentと結びつくrequestを表示してね。ということになる。

ストロングパラメーターに関しては、注意する点はuser_idとrequest_idは外部のキーをから持ってくるので、merge(=統合)させる点。

コメントを投稿するためのフォーム

ビューファイルでform_withを使用して、コメントをモデルに送信する。
この際に送信するモデルはcommentとrequestである。

<% if user_signed_in? %>
<%= form_with(model: [@request, @comment], local: true) do |form| %>
<%= form.text_area :text, placeholder: "コメントする", rows: "2" %>
<%= form.submit "SEND" %>
<% end %>
<% else %>
<strong><p>※※※ コメントの投稿には新規登録/ログインが必要です ※※※</p></strong>
<% end %>

if user_signed_in?でログインしているかどうかの条件分岐。
していなければそもそも投稿フォームが表示されない。

requestコントローラーのshowアクションに対しても、commentを表示させるための記述をしなければならない。

def show
@comment = Comment.new
@comments = @request.comments.includes(:user)
end

form_withで送信するために@commentを定義しておく。
また、showに投稿されているコメントを全て取得するためにアソシエーションを利用した記述を使って取得する。
@request(=> Request.find(params[:id]) )はbefore_actionでまとめて表記したので、ここでは省略している。


まとめて取得したコメントはeachを使って表示させる。

<h4><コメント一覧></h4>
<% @comments.each do |comment| %>
<p>
<strong><%= link_to comment.user.nickname, "/users/#{comment.user_id}" %></strong>
<%= comment.text %>
</p>
<% end %>

コメントを投稿したユーザー名をクリックするとそのユーザーのマイページへ飛べるように記述。

これで依頼に対してコメントしてくれたユーザーへ直接アクセスすることができる。
ここから派生してフォロー・フォロワーの機能があれば、ユーザー同士をつなげるなどできそう。

今日はここまで、細かいビューの調整とかはまた明日。