読者です 読者をやめる 読者になる 読者になる

mmyoji's diary

プログラミングとか日々のどうでもいいこととか

ネストできるコメント機能作るとき

がんばってRailsをnormalizeしましょう。はい。

以下のような仕様があるとする

  • 商品 ( Product ) にコメントできるようにしたい
  • ただし「コメントにコメントする」ような機能にしたい( Hacker News みたいな感じ)

この時、自前で実装してもいいんですが acts_as_commentable_with_threading を使うと比較的楽に実装できます。

awesome_nested_set に依存していて、 こちら の記事がとてもわかりやすかったので事前に目を通しておくといいと思います。

実装

とりあえずコメントをする User モデルがあるとします

$ rails g model user username:string email:string

商品 (Product) モデル

$ rails g model product name:string price:integer

gem 用の comment モデル作成

$ rails g acts_as_commentable_with_threading_migration

# すでに acts_as_commentable を使っていれば代わりに以下を実行 #トノコト
$ rails g acts_as_commentable_upgrade_migration

これで rake db:migrate してください

であとは以下を書くだけ

class Product < ActiveRecord::Model
  acts_as_commentable
end

コメントの作成

user = User.first
product = Product.first

comment = Comment.build_from(
  product, 
  user.id, 
  "I am a root comment."
)
# 自分で以下のように書くのと同じです
# Comment.new(
#   commentable: product,
#   user_id: user.id,
#   body: "I am a root comment."
# )
comment.save!

# commentに紐づく子commentの作成
comment.children.create!(
  user: user,
  commentable: product,
  body: "I am a child comment.",
)

# or set `parent_id`
child_comment = Comment.build_from(
  product,
  user.id,
  "I am another child comment.",
)
child_comment.update!(parent_id: comment.id)

form 組むのがなんかめんどくさそうですが、自分がなるべく楽できるようにがんばって仕様を捻じ曲げましょう。