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

如何在Rails应用中实现用户与爱好的关联创建/销毁切换按钮?

解决Rails中用户爱好关联的切换按钮问题

你的思路方向是对的,但确实没必要通过new页面来完成这个关联操作——因为关联只需要user_id和hobby_id两个参数,完全可以直接通过按钮触发创建/销毁请求,跳过中间的表单页面。下面是具体的实现方案:

第一步:先判断用户与爱好的关联状态

在/interests页面的视图中,我们需要先遍历所有爱好,判断当前登录用户是否已经关联了该爱好,从而动态显示「添加」或「移除」按钮:

<%# app/views/interests/index.html.erb %>
<% @hobbies.each do |hobby| %>
  <div class="hobby-item">
    <h4><%= hobby.name %></h4>
    <% if current_user.interests.exists?(hobby_id: hobby.id) %>
      <%# 已关联,显示移除按钮 %>
      <%= link_to '移除爱好', user_interest_path(current_user, current_user.interests.find_by(hobby_id: hobby.id)),
                  method: :delete,
                  class: "btn btn-danger",
                  data: { confirm: "确定要移除「#{hobby.name}」这个爱好吗?" } %>
    <% else %>
      <%# 未关联,显示添加按钮 %>
      <%= link_to '添加爱好', user_interests_path(current_user),
                  method: :post,
                  params: { interest: { hobby_id: hobby.id } },
                  class: "btn btn-primary" %>
    <% end %>
  </div>
<% end %>

第二步:完善控制器逻辑

修改InterestsController,处理创建和销毁关联的请求,同时确保操作的是当前登录用户的关联:

# app/controllers/interests_controller.rb
class InterestsController < ApplicationController
  before_action :set_current_user, only: [:index, :create, :destroy]
  before_action :set_user_interest, only: [:destroy]

  # /interests 页面展示逻辑
  def index
    @hobbies = Hobby.all # 可根据需求筛选爱好,比如热门爱好等
    @user_hobbies = @user.interests.includes(:hobby).map(&:hobby)
  end

  # 创建关联
  def create
    @interest = @user.interests.build(interest_params)
    if @interest.save
      redirect_to interests_path, notice: "成功添加爱好:#{@interest.hobby.name}"
    else
      redirect_to interests_path, alert: "添加爱好失败,请重试"
    end
  end

  # 销毁关联
  def destroy
    hobby_name = @interest.hobby.name
    @interest.destroy
    redirect_to interests_path, notice: "已移除爱好:#{hobby_name}"
  end

  private

  def set_current_user
    @user = current_user # 假设你用Devise或类似认证系统,current_user是当前登录用户
  end

  def set_user_interest
    @interest = @user.interests.find(params[:id])
  end

  def interest_params
    params.require(:interest).permit(:hobby_id)
  end
end

第三步:配置嵌套路由

为了更符合RESTful设计,建议使用嵌套路由(确保操作的是当前用户的兴趣):

# config/routes.rb
Rails.application.routes.draw do
  # 嵌套路由:用户的兴趣操作
  resources :users do
    resources :interests, only: [:index, :create, :destroy]
  end

  # 给/interests设置直接访问的路由
  get '/interests', to: 'interests#index'
end

为什么你的原有方案无法工作?

你之前通过new_interest_path跳转至new页面的问题在于:

  1. HTTP是无状态的,视图中创建的@interest实例在跳转后会被重新初始化,无法传递参数
  2. 创建关联应该用POST请求而非GET请求,GET请求用于获取资源,不应该修改数据
  3. 这种简单的关联操作不需要单独的表单页面,直接通过按钮传递参数即可完成

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:27:57