Ajax创建记录后重载ActiveRecordCollectionProxy并禁用点赞按钮
解决Ajax点赞后无需刷新即可禁用按钮的问题
看起来你已经搭好了基础的点赞功能,问题出在Ajax请求成功后没有更新前端按钮状态——目前只有页面加载时会根据服务器数据判断是否禁用按钮,Ajax提交后页面没有同步更新。下面是一步步的修复方案:
1. 先修正模型关联的小问题
首先注意Rails的has_many关联需要用复数形式,否则会引发查询错误:
# app/models/listing.rb class Listing < ActiveRecord::Base has_many :likes, foreign_key: :listing_id, dependent: :destroy # 把like改成likes复数 end
2. 优化视图:给按钮加唯一标识+简化禁用逻辑
修改点赞表单的按钮,给它一个基于listing ID的唯一ID(方便JS精准定位),同时去掉不安全的前端传user_id(改用控制器从current_user获取):
# app/views/likes/_form.html.erb <%= form_for(Like.new, remote: true) do |f| %> <%= f.hidden_field :listing_id, value: listing.id %> <%# 不再手动传user_id,控制器通过current_user自动关联 %> <% is_liked = listing.likes.pluck(:user_id).include?(current_user.id) %> <%= f.button "", class: "round-button btn-center #{'disabled' if is_liked}", id: "like-button-#{listing.id}", # 唯一ID,JS用来定位 disabled: is_liked, # 原生disabled属性才会真正禁用按钮 data: { disable_with: "<i class='fa fa-spinner fa-spin'></i>" } do %> <span class="glyphicon glyphicon-heart"></span> <% end %> <% end %>
3. 优化控制器:增加重复点赞校验+传递@listing给JS
在点赞控制器里,先校验用户是否已经点过赞(避免重复创建记录),同时获取对应的@listing,方便后续JS模板使用:
# app/controllers/likes_controller.rb class LikesController < ApplicationController before_filter :authenticate_user! def create @listing = Listing.find(params[:like][:listing_id]) # 先检查是否已经点赞,避免重复创建 if @listing.likes.exists?(user_id: current_user.id) respond_to do |format| format.js { render :create, status: :unprocessable_entity } end return end # 用current_user关联创建点赞,自动设置user_id @like = current_user.likes.build(listing: @listing) respond_to do |format| if @like.save current_user.create_activity(@like, "like") format.js else format.html { redirect_to root_url, notice: "Unable to proceed" } format.js end end end [...] end
4. 创建JS模板:Ajax成功后实时禁用按钮
新建app/views/likes/create.js.erb文件,这是Ajax请求成功后会自动执行的JS代码,用来更新按钮状态:
// 定位当前listing的点赞按钮 const likeButton = document.getElementById('like-button-<%= @listing.id %>'); // 禁用按钮+添加禁用样式 likeButton.disabled = true; likeButton.classList.add('disabled'); // 可选:把图标改成实心爱心(视觉反馈) likeButton.innerHTML = '<span class="glyphicon glyphicon-heart"></span>';
如果要处理重复点赞的错误情况,可以再写一段错误状态下的JS:
// app/views/likes/create.js.erb(当status为:unprocessable_entity时) alert('你已经给这个内容点过赞啦!'); // 恢复按钮的可点击状态 const likeButton = document.getElementById('like-button-<%= @listing.id %>'); likeButton.disabled = false; likeButton.innerHTML = '<span class="glyphicon glyphicon-heart"></span>';
原理说明
- 页面加载时,服务器根据用户是否已点赞渲染按钮的初始状态;
- 用户点击按钮后,Ajax提交请求到控制器,控制器校验并创建点赞记录;
- 成功后执行
create.js.erb,直接操作DOM禁用对应按钮,无需刷新页面; - 增加重复点赞校验,既避免数据库冗余,也给用户更友好的反馈。
内容的提问来源于stack exchange,提问作者Obed Lorisson
相关产品推荐
相关产品推荐

