1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Rails】(後編)投稿のコメントにさらにコメントしよう(備忘録)

Last updated at Posted at 2022-01-08

みなさん、こんにちは!
筆者は大学生限定のプログラミングスクール「GeekSalon」でメンターをしています!
興味のある方や話だけでも聞いてみてい方はぜひのぞいてみてください👍

さっそく今回の本題に入っていきます!
今回は投稿の詳細を表示するように、投稿に対してなされたコメントの詳細を表示する機能を実装していきます。

##記事を書くに至った背景
筆者は、投稿機能を用いてお店の情報を、投稿へのコメント機能を通じてお店の商品を、コメントへのコメントを通じて商品への口コミを記録できるようなプロダクトを実装しようと思い立ちました!
このようなプロダクトを完成させるためには、①投稿に対するコメントの詳細を見ることができる機能、そして②投稿に対するコメントにさらにコメントできる機能が必要になります。
そのため、コメントの詳細ページを実装する記事、コメントにさらにコメントできる機能を実装する記事を探したのですがなかなかいいものがなく、自力で実装することにしました。

この記事は筆者の実装の振り返りのようなものです。

上記で述べたように、①投稿に対するコメントの詳細を表示し、②コメントに対しさらにコメントできる機能の実装の2つを行っていきますので、記事も2本立てで行きます。今回はその(後編)です。

前編の記事はこちらから
【Rails】(前編)投稿のコメントの詳細ページを表示する

##実装環境
Ruby 3.0.2-1
Rails 6.1.4.1
(※投稿機能、投稿に対するコメント機能は実装済みという前提で記事を書いていきます。)

##実装① ~モデルの作成~

今回は、replyモデルを作成していきます。
コマンドプロンプトに以下を入力し、モデルを作りましょう

コマンドプロンプト
$ rails g model Reply content:string user:references comment:references
$ rails db:migrate

今回は、コメントに対するコメントのため、アソシエーションはtweetに対してではなく、commentに対して行いましょう。

次に、モデルのファイルに記述を加えていきましょう。

app/models/user.rb
has_many :replies, dependent: :destroy
app/models/comment.rb
has_many :replies, dependent: :destroy

##実装② ~コントローラーの作成~

次にrepliesコントローラーを作成します。

コマンドプロンプト
$ rails g controller replies

そして、作成したコントローラーに以下を記述していきます。

controller/replies_controller.rb
class RepliesController < ApplicationController

    before_action :authenticate_user!

    def create
        comment = Comment.find(params[:comment_id])
        reply = comment.replies.build(reply_params)
        reply.user_id = current_user.id
        if reply.save
            flash[:success] = "コメントしました"
            redirect_back(fallback_location: root_path)
        else
            flash[:success] = "コメントできませんでした"
            redirect_back(fallback_location: root_path)
        end
    end

    private
    def reply_params
        params.require(:reply).permit(:content)
    end

end

これでコントローラーが完成です。
次にルーティングも行っていきましょう。

##実装③ ~routes.rb~

routes.rbはこんな感じになっていると思います。

routes.rb
resources :tweets do
  resources :comments, only: [:create, :destroy, :show]
end

今回はコメントに対してコメントしたいので、コメントのresourcesに対してネスト構造をもう一つ設けてあげましょう。記述は以下の感じです。

routes.rb
resources :tweets do
  resources :comments, only: [:create, :destroy, :show] do
    resources :replies, only: [:create]
  end
end

これでrails routesをしてパスを確認すると、reolies#createのパスは、tweet_comment_repliesとなっていることがわかります。
これで、リプライをコメントと紐づけたパスを取得することができました。

##実装④ ~comments/show.html.erb~

ではViewページに記述を加えていきます。前編の記事で作成したcomments/show.html.erbファイルに、以下を記述してください。

comments/show.html.erb
#省略
<div class="reply-wrapper">
    <p>コメントのコメント一覧</p>
    <% @replies.each do |r| %>
        <div>
        <%= r.user.email unless r.user.blank? %>
        <br>
        <%= r.content %>
        </div>
        <br>
    <% end %>

    <% if user_signed_in? %>
        <%= form_with(model: [@tweet, @comment, @reply], local: true) do |f| %>
            <%= f.text_area :content %>
            <%= button_tag type: "submit" do %>
                <i class="far fa-comments"></i> コメントする
            <% end %>
        <% end %>
    <% end %>
</div>
#追記ここまで

<%= link_to "戻る", tweet_path(@comment.tweet_id) %>

これでViweページの完成です。
また、Viweページで@replyrepliesを用いることができるように、コントローラーに以下を記述しましょう。

comments_controller.rb
def show
    @comment = Comment.find(params[:id])
 #追記ここから
    @replies = @comment.replies
    @reply = Reply.new
 #追記ここまで
end

これで完成です。
rails sで確認してみてください!






??

おそらく、NoMethodError undefined method `~_path'というエラーが生じたとおもいます。
このエラーに対処してから記事を終わらせましょう。

##実装⑤ ~routes.rb その2~

replies#createのパスは、tweetcommentの両方のネスト構造の中にあります。しかしよく考えてください。コメントテーブルはコメントIDを持っているため、わざわざツイートテーブルと紐づけしなくてもコメントIDさえ取得すれば唯一無二のコメントを取得してくることができます。つまり、コメントを特定するにあたり、ツイートの情報はいらない(=ツイートと結びつけなくていい)のです。

そのため、今のroutes.rbの記述を以下のように変更しましょう。

routes.rb
#省略
resources :tweets do
  resources :comments, only: [:create, :destroy]
end

resources :comments, only: [:show] do
  resources :replies, only: [:create]
end
#省略

つまり、comments#showのパスだけtweetから独立させ、そして新たに定義したcomment#showに紐づける形でrepliesのネスト構造を作ってあげるのです。

comments#showはコメントのIDさえあれば親となるツイートの情報がなくてもコメントの詳細を呼び出せますし、またreplies#createもどのコメントに対するリプライかさえ特定できれば親であるツイートの情報を必要としません。そのため、このように独立させて記述させて問題がないのです。むしろ、独立させて記述したほうが余計なパス(ツイートのパス)と紐づくことがないため、より簡単にパスを記述できます。

またこのように記述を変えると、もう一つ変えないといけないものがあります。それは、tweets/show.html.erbから```comments/show.html.erb````に飛ぶためのリンク、つまりコメント詳細へ飛ぶためのリンクの記述です。現在は、

tweets/show.html.erb
#省略
<%= link_to "コメントの詳細へ", tweet_comment_path(@tweet.id, c.id) %>
#省略

とツイートに紐づいたリンクが記述されているはずなので、これを

tweets/show.html.erb
#省略
<%= link_to "コメントの詳細へ", comment_path(c.id) %>
#省略

のように書き直してあげましょう。これで完了です。

さて、改めてrails sしてたしかめてみてください。先ほどのエラーは解消されてコメントに対してコメントができるようになっているはずです。

ここまで実装お疲れ様でした。
もしよければ前編の記事もお読みください。
【Rails】(前編)投稿のコメントの詳細ページを表示する

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?