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

Rails 6 + Bootstrap 5 Ajax调用加载全部user_notes而非当前用户笔记问题

私有用户笔记显示问题:所有用户可查看他人笔记,Ajax更新冲突

我有一个user_notes关联表,关联adventure_id与user_id(belongs_to关联),包含longtext类型的:note字段。当前存在两个核心问题:

  • 页面加载及Ajax调用成功后,所有用户都能看到其他用户的笔记(笔记应为私有)
  • 用ERB的<% if %>条件包裹笔记局部视图实现私有显示时,会破坏Ajax无刷新更新功能,必须手动刷新页面才能看到修改

控制器里的查询逻辑是正确的,但JS的条件判断无效,Ajax和模态框/表单更新功能本身正常。


相关代码

user_notes_controller.rb

def index
  @adventure = Adventure.find(params[:adventure_id])
  @user = current_user
  @user_notes = current_user.user_notes.where(adventure: @adventure).order(created_at: :desc)
end

index.html.erb

<div class="container">
  <!-- New Note Form -->
  <div class="row mt-4 card">
    <div class="col-12">
      <h3 class="text-center">Add a New Note</h3>
      <h6 class="text-center">(SHIFT + RETURN/ENTER for a new line)</h6>

      <%= form_with(model: [@adventure, UserNote.new], url: adventure_user_notes_path(@adventure), local: false, method: :post, id: 'note_form') do |form| %>
        <%= form.text_area :note, oninput: 'this.style.height = "";this.style.height = this.scrollHeight + "px"', class: "form-control", placeholder: 'Add a new note...' %>
        <%= form.hidden_field :adventure_id, value: @adventure.id %>
        <%= form.hidden_field :user_id, value: @user.id %>
    </div>
      <div class="d-inline-flex justify-content-center">
        <%= form.submit 'Save Note', class: "btn btn-outline-success text-end" %>
      </div>
  </div>
      <% end %>

      <!-- Display Saved Notes -->
      <div class="container-fluid overflow-auto">
        <div id="user-notes-list">
          <%= render partial: 'user_notes/note', collection: @adventure.user_notes.order(created_at: :desc), as: :note, locals: { adventure_id: @adventure.id, user_id: @user.id } %>
        </div>
      </div>
      <div class="modal fade" id="editNoteModal" tabindex="-1" aria-labelledby="editNoteModalLabel" aria-hidden="true">
        <div class="modal-dialog modal-dialog-centered modal-dialog-scrollable">
          <div class="modal-content">
            <div class="modal-header">
              <h5 class="modal-title" id="editNoteModalLabel">Editing Note</h5>
              <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <div class="modal-body" id="editNoteModalContent">
              <!-- Content from _edit_form.html.erb will be loaded here -->
            </div>
          </div>
        </div>
      </div>
</div><!-- End Container -->

<script><!-- Modal for Edit Note Form -->
// Update the list of notes in the DOM after successful Ajax response
$(document).on('ajax:success', '#note_form', function (event, data, status, xhr) {
    $('#editNoteModal').modal('hide'); // Hide the modal

    // Check if the note belongs to the current user
    if (data.user_id === $('body').data('current-user-id')) {
        $('#user-notes-list').html(data); // Update the list of notes
    }
});

$(document).on('click', '.edit-note-btn', function () {
    const noteId = $(this).data('note-id');
    const adventureId = $(this).data('adventure-id');

    $.ajax({
        url: `/adventures/${adventureId}/user_notes/${noteId}/edit_form`,
        method: 'GET',
        dataType: 'html',
        success: function (formHtml) {
            $('#editNoteModalContent').html(formHtml); // Load the form HTML into modal content
            $('#editNoteModal').modal('show'); // Show the modal
        }
    });
});
</script>

_note.html.erb(局部视图)

<div class="user-note mt-2" id="note_<%= note.id %>">
  <div class="text-dark card d-block p-2"><%= simple_format(note.note) %>
  <!-- Edit and Delete buttons -->
    <button class="btn btn-outline-primary edit-note-btn" data-bs-toggle="modal" data-bs-target="#editNoteModal" data-note-id="<%= note.id %>" data-adventure-id="<%= adventure_id %>">Edit</button>
    <%= link_to 'Delete', adventure_user_note_path(adventure_id: note.adventure, id: note), method: :delete, remote: true, class: 'delete-note btn btn-outline-danger content-justify-center', data: { confirm: 'Are you sure?' } %>
  <!-- end Edit and Delete buttons -->
  </div>
</div>

已尝试的排查步骤

  • 在application.html.erb的body标签添加data-current-user-id="<%= current_user.id %>"用于JS条件判断,无效果
  • 在_note.html.erb中用<% if note.user_id == @user.id %>包裹内容,能实现私有显示但破坏Ajax无刷新更新
  • 尝试多种控制器中定义@user_notes的方式,均未解决问题

修复方案

1. 修正页面初始渲染的数据源

当前页面渲染笔记时用的是@adventure.user_notes(所有用户的笔记),而非控制器中已筛选的@user_notes(当前用户的笔记)。修改index.html.erb中的渲染代码:

<%= render partial: 'user_notes/note', collection: @user_notes, as: :note, locals: { adventure_id: @adventure.id, user_id: @user.id } %>

这一步解决页面加载时显示他人笔记的问题。

2. 完善控制器Ajax响应逻辑

确保create/update/destroy动作返回当前用户的笔记列表,而非所有用户的。更新user_notes_controller.rb:

def create
  @adventure = Adventure.find(params[:adventure_id])
  @user_note = current_user.user_notes.build(user_note_params)
  @user_notes = current_user.user_notes.where(adventure: @adventure).order(created_at: :desc)

  respond_to do |format|
    if @user_note.save
      format.html { redirect_to adventure_user_notes_path(@adventure) }
      format.js { render partial: 'user_notes/note', collection: @user_notes, as: :note, locals: { adventure_id: @adventure.id, user_id: current_user.id }, layout: false }
    else
      format.html { render :new }
      format.js { render json: @user_note.errors, status: :unprocessable_entity }
    end
  end
end

def update
  @adventure = Adventure.find(params[:adventure_id])
  @user_note = current_user.user_notes.find(params[:id])
  @user_notes = current_user.user_notes.where(adventure: @adventure).order(created_at: :desc)

  respond_to do |format|
    if @user_note.update(user_note_params)
      format.html { redirect_to adventure_user_notes_path(@adventure) }
      format.js { render partial: 'user_notes/note', collection: @user_notes, as: :note, locals: { adventure_id: @adventure.id, user_id: current_user.id }, layout: false }
    else
      format.html { render :edit }
      format.js { render json: @user_note.errors, status: :unprocessable_entity }
    end
  end
end

def destroy
  @adventure = Adventure.find(params[:adventure_id])
  @user_note = current_user.user_notes.find(params[:id])
  @user_note.destroy
  @user_notes = current_user.user_notes.where(adventure: @adventure).order(created_at: :desc)

  respond_to do |format|
    format.html { redirect_to adventure_user_notes_path(@adventure), notice: 'Note was successfully deleted.' }
    format.js { render partial: 'user_notes/note', collection: @user_notes, as: :note, locals: { adventure_id: @adventure.id, user_id: current_user.id }, layout: false }
  end
end

private

def user_note_params
  params.require(:user_note).permit(:note, :adventure_id)
end

同时移除表单中的<%= form.hidden_field :user_id, value: @user.id %>,通过current_user关联创建更安全。

3. 简化JS条件判断

现在控制器返回的已是当前用户的笔记列表,无需再做user_id判断,修改JS代码:

$(document).on('ajax:success', '#note_form', function (event, data) {
    $('#editNoteModal').modal('hide');
    $('#user-notes-list').html(data);
});

内容的提问来源于stack exchange,提问作者SubrosaGames

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 05:47:05