Rails应用评论模块AJAX失效,提交评论需刷新页面才显示
解决Rails评论模块AJAX提交后无需刷新显示的问题
看起来你已经把评论模块的核心功能搭好了,只是AJAX提交后的页面更新逻辑没处理到位。问题出在控制器的create动作返回了跳转而非评论的HTML片段,加上回复表单没开启AJAX支持,前端也没处理动态生成的回复表单事件。下面是一步步的修复方案:
1. 修改CommentsController的create动作
原来的redirect_back会让AJAX请求收到跳转响应,无法直接拿到新评论内容。我们需要区分HTML和AJAX请求,给AJAX返回评论的局部视图:
class CommentsController < ApplicationController before_action :authenticate_user! def create commentable = commentable_type.constantize.find(commentable_id) @comment = Comment.build_from(commentable, current_user.id, body) if @comment.save make_child_comment # 区分请求类型:HTML请求跳转,AJAX请求返回评论片段 respond_to do |format| format.html { redirect_back fallback_location: root_path, notice: 'Comment was successfully added.' } format.js { render partial: 'comments/comment', locals: { comment: @comment } } end else render :action => "new" end end # 其他私有方法保持不变... end
2. 创建单个评论的局部视图
新建app/views/comments/_comment.html.haml,用来渲染单条评论(包含回复按钮和回复表单),让AJAX请求能直接拿到可复用的评论HTML:
.comments-show .comment .media.mb-4 .d-flex.mr-3 .float-left.image - if comment.user.profile_image.present? .review-img = image_tag attachment_url(comment.user, :profile_image, :fit, 50, 50, format: "jpg") - else %img.review-img{:alt => "user profile image", :src => "https://img.icons8.com/bubbles/100/000000/user.png"}/ .media-body .small %b - if comment.user.username.present? #{comment.user.username} - else #{comment.user.full_name} .small.text-muted #{time_ago_in_words(comment.created_at)} ago .small = content_tag(:div, comment.body, style: "white-space: pre-wrap;") %br .comment-nav %a.comment-reply{:href => "#/", class: "btn btn-sm btn-link"} reply .reply-form # 给回复表单加上remote: true,开启AJAX提交 = simple_form_for @new_comment, remote: true 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 .field.form-group = f.text_area :body, class: 'form-control' .field.form-group{:style => "margin-bottom: 60px"} = submit_tag "Post Reply", class: 'btn btn-primary', style: "float: right;" %div{:style => "margin-left: 100px;"} = render partial: "comments/reply", locals: {comments: comment.children}
3. 简化_reply.html.haml
原来的_reply视图现在只需要循环渲染单个评论的局部视图即可:
- comments.each do |comment| = render partial: 'comments/comment', locals: { comment: comment }
4. 更新前端JS处理逻辑
修改comments.js.coffee,分别处理主评论表单和动态生成的回复表单的AJAX事件,把新评论插入到正确位置:
$ -> $('.comment-reply').click -> $(this).closest('.comment').find('.reply-form').toggle() return jQuery -> # 处理主评论表单的AJAX提交 $(".comment-form") .on "ajax:beforeSend", (evt, xhr, settings) -> $(this).find('textarea') .addClass('uneditable-input') .attr('disabled', 'disabled'); .on "ajax:success", (evt, data, status, xhr) -> $(this).find('textarea') .removeClass('uneditable-input') .removeAttr('disabled') .val(''); # 把新评论插入到评论列表顶部(可根据需求改到底部) $(this).next('.scrollable').find('.comments-show').first().before(xhr.responseText) # 用事件委托处理动态生成的回复表单AJAX事件 $(document).on "ajax:beforeSend", ".reply-form form", (evt, xhr, settings) -> $(this).find('textarea') .addClass('uneditable-input') .attr('disabled', 'disabled'); $(document).on "ajax:success", ".reply-form form", (evt, data, status, xhr) -> $(this).find('textarea') .removeClass('uneditable-input') .removeAttr('disabled') .val(''); # 把回复插入到父评论的子评论区域顶部 $(this).closest('.comment').find('div[style="margin-left: 100px;"]').prepend(xhr.responseText) # 提交后自动隐藏回复表单 $(this).closest('.reply-form').toggle()
修复逻辑说明
- 控制器不再跳转,给AJAX请求返回新评论的HTML片段,让前端能直接插入页面
- 回复表单加上
remote: true,确保回复操作也是AJAX提交 - 用事件委托处理回复表单的AJAX事件,避免动态生成的表单无法触发事件
- 明确新评论的插入位置:主评论插入到列表顶部,回复插入到父评论的子评论区域
这样修改后,无论是主评论还是回复,提交后都会立即显示在页面上,无需刷新!
内容的提问来源于stack exchange,提问作者Christian Dziwornu
相关产品推荐
相关产品推荐

