bebetem.com 대댓글

[bebetem.com 대댓글]

0. Gem 소개

act_as_commentable_with_threadingact_as_commentable에 댓글에 대한 댓글(대댓글) 기능을 추가시킨 gem 입니다.

1. 설치법

Github readme.md 참고하세요. 여기에는 간단하게 코드만 옮겨왔습니다.

Install

<Gemfile>
    gem 'acts_as_commentable_with_threading'

<terminal>
> bundle install
> rails generate acts_as_commentable_with_threading_migration

설치가 끝나면 Comment 모델이 생성되고, comments table이 생성됩니다.

schema.rb

create_table "comments", force: :cascade do |t|
    t.integer  "commentable_id"
    t.string   "commentable_type"
    t.string   "title"
    t.text     "body"
    t.string   "subject"
    t.integer  "user_id",          null: false
    t.integer  "parent_id"
    t.integer  "lft"
    t.integer  "rgt"
    t.datetime "created_at"
    t.datetime "updated_at"
end

add_index "comments", ["commentable_id", "commentable_type"], name: "index_comments_on_commentable_id_and_commentable_type", using: :btree

add_index "comments", ["user_id"], name: "index_comments_on_user_id", using: :btree

commentable_id : 댓글에 대상이 되는 객체의 아이디

user_id : 댓글 소유자 아이디

parent_id : 대댓글의 시작이되는 첫 댓글 아이디 (gem에서는 root_comment라 부릅니다.)

2. 사용법

댓글에 대상이되는 model에 acts_ac_commentable을 추가합니다.

class Article < ActiveRecord::Base
    acts_as_commentable
end

댓글을 build 할 때는 댓글의 대상이 되는 @article과 댓글을 작성하는 유저의 아이디 @user_who_commented.id 를 함께 넘겨줍니다.

@comment = Comment.build_from( @article, @user_who_commented.id, "Hey guys this is my comment!" )

기본적으로 생성되는 comement.rb는 다음과 같은 validation이 적용되어 있습니다.

belongs_to :commentable, :polymorphic => true

belongs_to :user

:polymorphic => true 는 commentable이 하나의 model이 아닌 여러 model이 될 수 있게 해줍니다. schema.rb에서 commentable_idcommentable_type 컬럼이 있었죠. Commentable 이라는 모델은 없지만, polymorphic-association을 통해서 어떤 모델이라도 될 수 있게 됩니다. Rails guide의 polymorphic-association 부분을 참고하세요. 이전 버전이긴 하지만 Ryan Bates의 RailsCast에서도 polymorphic-assocation을 다루고 있습니다.

3. Controller

gem에서 controller를 생성해주지는 않습니다. Controller는 직접 구성해야 되는데, 이 gem을 만든 Dustin Fisher의 블로그에 예제코드가 있습니다.

아래 코드는 베베템 의 리뷰 시스템을 만들면서 사용한 코드입니다.

class CommentsController < ApplicationController  
    #TODO: user authentication

    def index
        redirect_to root_path
    end
  
    def new
        @item = Item.find_by(id: params[:item_id])
        @comment = Comment.build_from(@item, current_user.id, "")
    end

    def show
        @comment = Comment.find_by(id: params[:id])
        @item = Item.find_by(id: @comment.commentable_id)
        if current_user
            @new_comment    = Comment.build_from(@item, current_user.id, "")  
        end
    end
    

    def create
        commentable = commentable_type.constantize.find(commentable_id)
        @comment = Comment.build_from(commentable, current_user.id, body)

        respond_to do |format|
          if @comment.save
            make_child_comment
            format.html  {
              if root_comment_id
                redirect_to comment_path(root_comment_id)
              else
                redirect_to item_path(commentable_id) 
              end
            }
            format.js
          else
            format.html  { render :action => "new" }
            format.js
          end
        end
    end

    def destroy
        @comment = Comment.find_by(id: params[:id])
        @comment.destroy
        respond_to do |format|
          format.html { redirect_to(:back)}
          format.js
        end
    end

    private

    def comment_params
        params.require(:comment).permit(:body, :commentable_id, :commentable_type, :comment_id, :root_comment_id)
    end

    def root_comment_id
        comment_params[:root_comment_id]
    end

    def commentable_type
        comment_params[:commentable_type]
    end

    def commentable_id
        comment_params[:commentable_id]
    end

    def comment_id
        comment_params[:comment_id]
    end

    def body
        comment_params[:body]
    end

    def make_child_comment
        return "" if comment_id.blank?
        
        parent_comment = Comment.find comment_id
        @comment.move_to_child_of(parent_comment)
    end
end