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
相关产品推荐
相关产品推荐

