acts_as_commentable_with_threadingを使ってみる
親子関係をもったコメント機能を簡単に実装できる、acts_as_commentable_with_threadingを使ってみたのでメモ。
こんな感じ。
GitHubのREADMEだけだと情報が少なかったんだけど、ここのまとめが素晴らしかった。
ただ、この記事のままだとエラーになるのでそこを修正、加えてコメントの削除がしたかったので追加してます。
ではでは、やってみましょう。
Gemfile.
gem 'acts_as_commentable_with_threading'
で、bundle installをする。
routes.rb
resources :comments
今回用のresourcesを追加する。
コメント管理用モデルを作成
コメントを保存しておくためのモデルを作成。
rails generate acts_as_commentable_with_threading_migration
で、rake db:migrateする。
そうすると、Commentsというテーブルが作成される。テーブルの中身はこんな感じ。
CREATE TABLE "comments" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "commentable_id" integer, "commentable_type" varchar(255), "title" varchar(255), "body" text, "subject" varchar(255), "user_id" integer NOT NULL, "parent_id" integer, "lft" integer, "rgt" integer, "created_at" datetime, "updated_at" datetime); CREATE INDEX "index_comments_on_commentable_id_and_commentable_type" ON "comments" ("commentable_id", "commentable_type"); CREATE INDEX "index_comments_on_user_id" ON "comments" ("user_id");
コメント機能を導入したいモデルを編集
次に、このコメント機能を取り入れたいモデルの編集。
今回はProfileというモデルに入れたかったので、app/model/profile.rbを編集。
acts_as_commentableを加えています。
class Profile < ActiveRecord::Base acts_as_commentable end
コメントコントローラを作成
app/controllers/comments_controller.rbを作ります。
createの一部が参照サイトと一部異なっています。
そして、コメントを削除できるように、destroyを追加しています。
class CommentsController < ApplicationController def create commentable = commentable_type.constantize.find(params["comment"]["commentable_id"]) @comment = Comment.build_from(commentable, current_user.id, body) respond_to do |format| if @comment.save make_child_comment format.html { redirect_to(:back, :notice => 'Comment was successfully added.') } else format.html { render :action => "new" } end end end def destroy @comment = Comment.find(params[:id]) @comment.destroy respond_to do |format| format.html { redirect_to(:back, notice => 'コメントが削除されました。') } end end private def comment_params params.require(:comment).permit(:body, :commentable_id, :commentable_type, :comment_id) end def commentable_type comment_params[:commentable_type] 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
コメント機能を導入したいコントローラを編集
def show @profile = Profile.find(params[:id]) @new_comment = Comment.build_from(@profile, current_user.id, "") end
あとは、Viewファイルを作ります。
コメント機能を導入したいビューを編集
<%= render partial: "comments/template", locals: {commentable: @profile, new_comment: @comment} %>
app/view/comments配下のビューを作成
_template.html.erb
<div class="comments-header"> <h4> <%= commentable.comment_threads.count == 0 ? "no" : commentable.comment_threads.count %> comments </h4> </div> <%= render partial: "comments/form", locals: {new_comment: new_comment} %> <div class="comments-container"> <%= render partial: "comments/reply", locals: {comments: commentable.root_comments} %> </div>
_form.html.erb
<%= form_for @new_comment do |f| %> <%= f.hidden_field :commentable_id, value: @new_comment.commentable_id %> <%= f.hidden_field :commentable_type, value: @new_comment.commentable_type %> <div class="field form-group"> <%= f.text_area :body, class: 'form-control' %> </div> <div class="field form-group"> <%= submit_tag "Post comment", class: 'btn btn-primary' %> </div> <% end %>
_reply.html.erb
<% comments.each do |comment| %> <div class="comments-show"> <div class="comment"> <p><%= simple_format(comment.body) %><br></p> <div class="comment-nav"> <a href="#" class="comment-reply">返信する</a> | <%= link_to '削除する', comment, method: :delete, data: { confirm: 'コメントを削除します。よろしいですか?' } %> </div> <div class="reply-form"> <%= form_for @new_comment do |f| %> <%= f.hidden_field :commentable_id, value: @new_comment.commentable_id %> <%= f.hidden_field :commentable_type, value: @new_comment.commentable_type %> <%= f.hidden_field :comment_id, value: comment.id %> <div class="field form-group"> <%= f.text_area :body, class: 'form-control' %> </div> <div class="field form-group"> <%= submit_tag "Post Reply", class: 'btn btn-primary' %> </div> <% end %> </div> </div> <%= render partial: "comments/reply", locals: {comments: comment.children} %> </div> <% end %>
CSS編集
最後にCSSを編集します。ここはまだいじる必要があると思う。
.comments-header { border-bottom: 1px dotted gray; margin-bottom: 10px; } .comments-container { p { margin-bottom: 0px; } .comment-nav { margin-left: 5px; margin-bottom: 10px; a { font-size: 10px; font-weight: bold; color: #888; } } } .reply-form { display: none; } .comments-show { margin-left: 25px; } .comment { background-color: #fff; padding: 8px; margin: 5px; border-radius: 10px; }
以上です。便利だなぁ。