2016-01-19 2 views
2

Я работаю над своим первым проектом в рубине на рельсах и нуждаюсь в реализации комментариев и ответов на них. Я столкнулся с отображением ответов под каждым комментарием, а также, если у любого ответа есть ответы ребенка, они должны отображаться под ним. Структура будет каким-то образом, как следует.Вложенные комментарии и ответы в 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 комментария рассматривается как ответ на первый ответ на первый комментарий. любезная помощь в отношении этой вложенной структуры, что я могу управлять ею наилучшим образом. Таблица комментариев также имеет связь с таблицей проекта и пользовательской таблицей. предлагать лучший способ без драгоценного камня, поскольку я уже пробовал многие из них, но они ограничены в уровне глубины.

+1

Вы посмотрели на драгоценный камень '' cap_tree''? Это позволяет вашим моделям ActiveRecord действовать как узлы в структуре данных дерева. https://github.com/mceachen/closure_tree – apebeast

+0

Да, но он не работает. я попытался в соответствии с его документацией, но не смог –

+0

'act_as_tree' лучше, чем закрытие –

ответ

0

Я не обязательно хочу предлагать только драгоценный камень, так как вы сказали, что уже сделали свою домашнюю работу, но я использовал драгоценный камень почтового ящика (https://github.com/mailboxer/mailboxer), прежде чем для такого же типа использование случай хороший эффект. По общему признанию, мне пришлось немного взломать его, чтобы обработать некоторые случаи краев, но я думаю, что в вашем конкретном сценарии он будет обрабатывать вещи просто отлично. Возможно, более того, даже если вам нужно внести некоторые изменения, это, вероятно, лучше, чем сворачивать с нуля.

С учетом этого структуры данных, о которой вы описали, достаточно, чтобы сделать то, о чем вы просите. Последний шаг будет просто создать ассоциацию на модели Rails:

class Comment < ActiveRecord::Base 
    has_one :parent, class: 'Comment' 
end 

При этом установлено, вы просто должны убедиться, что ваши взгляды отображать многопоточность должным образом.

+0

ему также нужно будет добавить foreign_key: "parent_id" – joem

+0

Действительно? Я думал, что магия Rails получила имя внешнего ключа от имени ассоциации, но вы можете быть правы ... –

1

Это грубый набросок одного подхода к этому (некоторые элементы могут отсутствовать, то вполне может быть более эффективные способы и могут быть явные ошибки, но мы надеемся, что это может быть полезно):

=> Комментарий has_many :replies, dependent: :destroy

=> комментарий будет также необходимо accepts_nested_attributes_for :replies

=> Ответить belongs_to :comment

=> и, очевидно, нужно belongs_to :user

=> Комментарий будет необходимо 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 действительно кажется полезным для этого. Если раньше использовать почтовый ящик Mailboxer, я бы не рекомендовал этого - поскольку настройка не всегда прямолинейна.

10

We've done this before. Там также RailsCast об этом ..

enter image description here

Термин вы ищете является 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, пока их больше нет. Хотя для выполнения этой обработки потребуется немного обработки БД, она будет отображать комментарии с вложением.

-

Если вы хотите добавить ответ и т.д., вы просто должны заполнить "родительский" 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 
+0

Спасибо @richpeck. Четко объяснено и легко следовать. – RuNpiXelruN

+0

Это было бы быстрее, если бы вы ввели идентификатор проекта напрямую, а не использовали ассоциацию. Меньше поиска объектов. –