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

Rails实现无刷新点赞/取消点赞功能技术求助

Rails实现无刷新点赞/取消点赞功能求助

我正在搭建一个包含帖子(Post)和点赞(Like)模型的网站,需求是用户仅能对帖子点赞一次,点赞后按钮变为“取消点赞”,且操作时无需跳转页面即可更新状态。目前实现有难度,希望得到指引。

现有代码

点赞按钮模板 /likes/_likes.html.erb

<% liked = @post.likes.find { |like| like.user_id == current_user.id} %>
<div class="likes">
    <% if liked %>
      <%= button_to 'Unlike', post_like_path(@post, liked), method: :delete %>
    <% else %>
      <%= button_to 'Like', post_likes_path(@post), method: :post %>
    <% end %>
    <%= @post.likes.count %><%= (@post.likes.count) == 1 ? 'Like' : 'Likes'%>
</div>

Likes控制器代码

class LikesController < ApplicationController
    before_action :find_post
    before_action :find_like, only: [:destroy]

    def create
        if (!already_liked?)
            @post.likes.create(user_id: current_user.id)
        end
    end

    def destroy
        if (already_liked?)
            @like.destroy
        end
    end

    private

    def already_liked?
        Like.where(user_id: current_user.id, post_id:
        params[:post_id]).exists?
    end

    def find_post
        @post = Post.find(params[:post_id])
    end

    def find_like
       @like = @post.likes.find(params[:id])
    end
end

包含点赞部分的视图代码

<div class="post-display">
    <% if @post.title %>
        <h1><%= @post.title %></h1>
    <% end %>
    <% if @post.user %>
        Post by <%= @post.user.email %>
    <% end %>
    <% if @post.price %>
        <p>$<%= sprintf "%.2f", @post.price %></p>
    <% end %>
    <% if @post.description %>
        <p><%= @post.description %></p>
    <% end %>
    <% if @post.image.present? %>
        <%= image_tag @post.image.variant(:small) %>
    <% end %>

    <%= render 'likes/likes' %>
</div>

<% if current_user == @post.user %>
    <%= link_to "Edit", edit_post_path(@post) %>

    <%= button_to "Delete", @post, method: :delete %>
<% end %>

<% if @post.comments.count > 0 %>
    <div class="post-comments">
        <h2 class="post-comments-headline">Comments</h2>
        <%= render @post.comments %>
    </div>
<% end %>

<h2>Add a comment:</h2>
<%= render 'comments/form' %>

无刷新点赞实现步骤

1. 修改控制器支持JS响应

在create和destroy方法末尾添加响应JS的逻辑,让控制器能返回AJAX所需的内容:

def create
    if (!already_liked?)
        @post.likes.create(user_id: current_user.id)
    end
    respond_to do |format|
        format.js
    end
end

def destroy
    if (already_liked?)
        @like.destroy
    end
    respond_to do |format|
        format.js
    end
end

2. 创建JS模板更新页面

在app/views/likes/目录下创建两个JS模板文件,用于替换页面上的点赞区域:

create.js.erb

// 用最新的点赞模板替换页面中的点赞区域
$('.likes').html("<%= j render 'likes/likes' %>");

destroy.js.erb

// 同样替换点赞区域的内容
$('.likes').html("<%= j render 'likes/likes' %>");

注:j是escape_javascript的简写,用于转义HTML内容,避免JS语法错误。

3. 给按钮添加AJAX属性

修改_likes.html.erb中的button_to,添加remote: true让Rails用AJAX发送请求:

<% liked = @post.likes.exists?(user_id: current_user.id) %>
<div class="likes">
    <% if liked %>
      <%= button_to 'Unlike', post_like_path(@post, liked), method: :delete, remote: true %>
    <% else %>
      <%= button_to 'Like', post_likes_path(@post), method: :post, remote: true %>
    <% end %>
    <%= @post.likes.count %><%= @post.likes.count == 1 ? ' Like' : ' Likes'%>
</div>

这里顺便优化了点赞判断逻辑,用exists?比find更高效,无需加载整个点赞对象。

4. 确保页面引入必要的JS库

确认application.js中包含jQuery和Rails UJS(Rails 7+可用Turbo替代,将remote: true换成data: { turbo: true }即可):

//= require jquery
//= require rails-ujs

代码优化建议

  1. 模型层关联优化
    在Post模型中添加辅助方法,简化点赞判断:
class Post < ApplicationRecord
    has_many :likes, dependent: :destroy

    def liked_by?(user)
        likes.exists?(user_id: user.id)
    end
end

之后在视图中可直接用@post.liked_by?(current_user)替代原有判断,代码更清晰。

  1. 控制器逻辑简化
    用模型层的方法替换控制器中的already_liked?:
def already_liked?
    @post.liked_by?(current_user)
end
  1. 视图代码简化
    用Rails内置的pluralize方法简化点赞计数显示:
<%= pluralize(@post.likes.count, 'Like') %>

一行代码即可替代原有的计数+单数/复数判断。

  1. 数据库层面防重复
    在Like模型添加唯一性验证,确保数据库层也能阻止重复点赞:
class Like < ApplicationRecord
    belongs_to :post
    belongs_to :user
    validates :user_id, uniqueness: { scope: :post_id }
end

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 18:26:17