我正在用 Ruby on rails 制作一个应用程序,类似于 Reddit
,在项目中,我决定使用 polymorphic association
在 Comment
模型上使用递归。
递归删除 文章 <- 注释 <- 注释等
问题是,当我删除文章时,该文章取决于并在has_many
关联上使用:delete_all
(或:destroy
,已经尝试过了),它只会删除第一级评论。
同样的方式发生在Comments
,只有第一级回复被删除,我真的不希望孤儿评论在那里。
问题是,在这种情况下如何实现递归删除?
模型/文章.rb:
class Article < ActiveRecord::Base
belongs_to :user
has_and_belongs_to_many :tags
has_many :comments, as: :commentable , :dependent => :delete_all
end
models/comment.rb:
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :commentable, polymorphic: true
has_many :comments, as: :commentable , :dependent => :delete_all
end
articles_controller.rb:
def destroy
@article = Article.find(params[:id])
@comments = @article.comments.destroy
@article.destroy
redirect_to articles_path
end
comments_controller.rb:
class CommentsController < ApplicationController
before_action :find_commentable
.
.
.
def create
@comment = @commentable.comments.new(comment_params)
if @comment.save
redirect_to :back, notice: 'Your comment was successfully posted!'
else
redirect_to :back, notice: "Your comment wasn't posted!"
end
end
private
def comment_params
params.require(:comment).permit(:body, :user_id)
end
def find_commentable
@commentable = Comment.find_by_id(params[:comment_id]) if params[:comment_id]
@commentable = Article.find_by_id(params[:article_id]) if params[:article_id]
end
end
视图/文章/显示.html.erb
.
.
.
<ul>
<%= render(partial: 'comments/comment', collection: @article.comments) %>
</ul>
观点/评论/_comment.html.erb
<li>
<%= comment.body %> -
<small>Submitted <%= time_ago_in_words(comment.created_at) %> ago by <%= User.find(comment.user_id).name %></small>
<%= form_for [comment, Comment.new] do |f| %>
<%= f.hidden_field(:user_id , :value => current_user.id) %>
<%= f.text_area :body, placeholder: "Add a Reply", required: true %><br/>
<%= f.submit "Reply" %>
<% end %>
<ul>
<%= render partial: 'comments/comment', collection: comment.comments %>
</ul>
</li>
在评论和文章中使用 :destroy
而不是:delete_all
才能级联正常工作,因为删除不会触发回调。
另请注意@comments = @article.comments.destroy
不会在这里执行任何操作(您有一个CollectionProxy
因此它将像这样运行),您应该改用destroy_all
。但是,仅此一项无法正确解决递归删除问题,并且只会删除顶级注释的评论,并就此停止。实际上,如果您使用:destroy
,则根本不需要此行。