【Rails】 코멘트 기능의 구현

소개



블로그 같은 웹 서비스에 코멘트 기능을 추가해 보았습니다.
자신의 메모용, 그리고 같은 기능을 구현하려고 하는 초학자 분의 참고가 되면 다행입니다!

전제



Ruby : 2.6.4
Rails : 5.2.3

사용자 인증에 devise를 사용하고 있습니다.

Comment Model 작성



User 모델의 사용자가 Post 모델에 주석을 달 수 있도록 합니다.
구현 방법으로서는, 팔로우 기능과 같이 중간 테이블을 준비해, 그 중간 테이블(Comment Model)의 content 컬럼에
실제 주석을 추가합니다.
$ rails g model comment content:string user:references post:references
$ rails db:migrate

user.rb
  has_many :comments

post.rb
  has_many :comments

comment.rb
class Comment < ApplicationRecord
  belongs_to :user
  belongs_to :post
end

comment.rb에 관한 것이지만, 수동으로 실수로 post_id와의 연관이 잘 작동하지 않는 상태에서
코멘트의 테스트를 행해 버려, 외래 키가 nil이 되어 버려 에러가 되어 버렸습니다.
이 문제의 해결은

comment.rb
class Comment < ApplicationRecord
  belongs_to :user
  belongs_to :post, optional: true
end

이 방법으로 optional: true를 추가하여 (일시적으로) 해결할 수 있습니다.
여기서 자동 테스트의 고마움을 깨달았습니다 (웃음)
외래 키의 nil을 허가하는 패턴은 별로 없다고 생각하기 때문에, 사용하는 것은 거기까지 없을까라고 생각합니다.

컨트롤러 작성



comments_controller.rb 만들기
$ rails g controller comments

comments_controller.rb
class CommentsController < ApplicationController
  before_action :authenticate_user!

  def create
    post = Post.find(params[:post_id])
    @comment = post.comments.build(comment_params)
    @comment.user_id = current_user.id
    if @comment.save
      flash[:success] = "コメントしました"
      redirect_back(fallback_location: root_path)
    else
      flash[:success] = "コメントできませんでした"
      redirect_back(fallback_location: root_path)
    end
  end

  private

    def comment_params
      params.require(:comment).permit(:content)
    end
end


create 액션에 대해.
@comment.user_id = current_user.id를 작성하는 이유로,
위의 2행만으로는 코멘트를 한 사용자의 연관을 할 수 없기 때문에 쓰고 있습니다.

라우팅



routes.rb
  resources :posts do
    resources :comments, only: [:create]
  end

보기



자신의 경우는 Post의 show.html.erb에 코멘트 일람과 폼을 추가하고 싶었기 때문에 여기에 추가합니다.

app/views/posts.show.html.erb
<div class="comment-wrapper border-top mb-10">
  <p class="mt-5">コメント一覧</p>
  <% @comments.each do |c| %>
    <div>
      <% unless c.user.blank? %>
        <a href="<%= user_path(c.user_id) %>"><%= image_tag c.user.image.to_s,
          class:"rounded-circle icon_image mr-3 mb-3"%></a>
        <% end %>
      <%= c.user.username unless c.user.blank? %>
      <br />
      <%= c.content %>
    </div>
    <br />
  <% end %>
  <% if user_signed_in? %>
    <%= form_with(model: [@post, @comment], local: true) do |f| %>
      <%= f.text_area :content, class: "form-control", rows: 5 %>
      <%= button_tag type: "submit", class: "btn btn-success float-right mt-1" do %>
        <i class="far fa-comments"></i> コメントする
      <% end %>
    <% end %>
  <% end %>
</div>

특히 어렵지는 않지만 form_with(model: [ @post , @comment ], local: true) do |f|
comment가 post에 붙어 있기 때문에 배열로 합니다.

posts_controller.rb
  def show
    @post = Post.find(params[:id])
    @comments = @post.comments
    @comment = @post.comments.build
  end

show.html.erb 내에서 사용하는 @comment@comments은 위와 같습니다.

완성



로그인하지 않았을 때



로그인 시



끝에



코멘트 삭제 기능을 붙여 잊고 있었으므로 구현합니다.
뭔가 잘못된 점 등 있으면 댓글이나 트위터로 부탁드립니다!

좋은 웹페이지 즐겨찾기