You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:25:08