我正在研究我在ruby on rails上的第一个项目,需要在其上实现注释和回复功能。我面临着在每条评论下显示回复以及是否有任何回复都需要在其下显示的子回复。 结构将如何如下。
first comment
Reply to first comment
reply to first comment first reply
reply to first comment
Second comment
Reply to second comment
并且这个嵌套结构继续。 我只有一个表用于这些所有注释与父键作为回复。 表结构如下
Id | Comment_body | parent_id | user_id | project_id
1 comment 2 2
2 comment/reply 1 2 2
3 comment/reply 2 2 2
第二条评论被视为第一条评论的回复,而第3条评论被视为第一条评论第一次回复时的回复。 请帮助我了解如何以最佳方式管理它的嵌套结构。 注释表还与项目表和用户表关联。 建议没有宝石的最佳方式,因为我已经尝试了很多,但它们的深度水平有限。
答案 0 :(得分:11)
We've done this before。关于它还有一个RailsCast ..
您正在寻找的术语是recursion - 自我复制。
使用您可以使用acts_as_tree
:has_many / belongs_to
#app/models/comment.rb
class Comment < ActiveRecord::Base
belongs_to :project
belongs_to :parent, class_name: "Comment" #-> requires "parent_id" column
has_many :replies, class_name: "Comment", foreign_key: :parent_id, dependent: :destroy
end
这将允许以下内容:
#app/views/projects/show.html.erb
<%= render @project.comments %>
#app/views/comments/_comment.html.erb
<%= comment.body %>
<%= render comment.replies if comment.replies.any? %>
递归发生在render comment.replies
- 它将继续循环遍历replies
,直到没有更多。虽然这需要进行一些DB处理,但它会显示带有嵌套的注释。
-
如果你想添加回复等,你只需要填充&#34;父母&#34; ID:
#config/routes.rb
resources :projects do
resources :comments #-> url.com/projects/:project_id/comments/:id
end
end
#app/views/comments/_comment.html.erb
<%= form_for [comment.project, comment.new] do |f| %>
<%= f.hidden_field :parent_id, comment.parent.id %>
<%= f.text_field :body %>
<%= f.submit %>
<% end %>
上述内容将提交至comments#create
操作:
#app/controllers/comments_controller.rb
class CommentsController < ApplicationController
def create
@project = Project.find params[:project_id]
@comment = @project.comments.new comment_params
end
private
def comment_params
params.require(:comment).permit(:parent_id, :body)
end
end
答案 1 :(得分:1)
这是对此的一种方法的粗略概述(某些元素可能缺失,可能有更好的方法,可能存在明显的错误,但希望这可能有用):
=&GT;评论has_many :replies, dependent: :destroy
=&GT;评论还需要accepts_nested_attributes_for :replies
=&GT;回复belongs_to :comment
=&GT;两者显然都需要belongs_to :user
=&GT;评论需要belong_to
帖子/文章等。
在Routes.rb中,您可能希望在回复中嵌套回复
resources :comments do
resources :replies
end
如何将这些与帖子/文章模型相结合是另一个问题。
我们需要一个CommentsController
class CommentsController < ApplicationController
def index
@users = User.all
@inquiries = Inquiry.all
end
def new
@user = User.find_by(id: params[:user])
@post = Post.find_by(id: params[:post])
@comment = @post.inquiries.new
@message = @comment.replies.build
end
def create
@user = User.find_by(id: params[:user_id])
@post = Post.find_by(id: params[:post_id])
@comment = Comment.create!(comment_params) #define these below
@comment.user << @user
redirect_to #somewhere
end
回复控制器:
class RepliesController < ApplicationController
before_action do
@comment = Comment.find(params[:comment_id])
end
def index
@replies = @comment.replies
@reply = @comment.replies.new
end
def new
@reply = @comment.replies.new
end
def create
@reply = @comment.replies.new(reply_params)
#redirect somewhere
end
然后,您可以根据上述内容构建一些视图。我应该补充一点,closure_tree
gem确实看起来很有用。之前我曾经使用过Mailboxer gem,但我不建议这样做 - 因为定制并不总是直截了当。
答案 2 :(得分:0)
我不一定只想推荐一个宝石,因为你已经说过你已经完成了你的作业,但是我已经使用了邮箱宝石,({{ 3}}),之前为同一种用例效果良好。不可否认,我不得不破解它以处理一些边缘情况,但我认为在您的特定情况下,它会处理好的事情。也许更重要的是,即使你必须做出一些改变,这可能比从头开始自己做更好。
话虽如此,您所描述的数据结构已经足够,它可以满足您的要求。最后一步只是在你的Rails模型上建立关联:
class Comment < ActiveRecord::Base
has_one :parent, class: 'Comment'
end
通过该设置,您只需确保您的视图正确显示您的线程。