侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1823 篇文章
  • 累计收到 0 条评论

实现用户关注功能

2025-12-12 / 0 评论 / 4 阅读

题目

实现用户关注功能

信息

  • 类型:问答
  • 难度:⭐⭐

考点

ActiveRecord关联设计, RESTful路由设计, 数据库迁移, 回调函数使用

快速回答

实现用户关注功能的核心步骤:

  • 创建Relationship中间表模型处理关注关系
  • 设置用户模型的自连接多对多关联:has_many :active_relationshipshas_many :passive_relationships
  • 设计嵌套路由:resources :users do
    resources :relationships, only: [:create, :destroy]
    end
  • Relationship模型中添加唯一性验证防止重复关注
  • 控制器中使用current_user.follow(other_user)实现关注逻辑
## 解析

1. 原理说明

用户关注功能本质是多对多自连接关系:
- 一个用户(follower)可以关注多个其他用户(followed)
- 一个用户可以被多个其他用户关注
通过中间表relationships存储关联关系,其中包含follower_idfollowed_id两个外键。

2. 代码实现

数据库迁移文件(db/migrate/xxx_create_relationships.rb)

class CreateRelationships < ActiveRecord::Migration[7.0]
  def change
    create_table :relationships do |t|
      t.references :follower, foreign_key: { to_table: :users }
      t.references :followed, foreign_key: { to_table: :users }
      t.timestamps
    end
    # 添加复合索引防止重复关注
    add_index :relationships, [:follower_id, :followed_id], unique: true
  end
end

用户模型(app/models/user.rb)

class User < ApplicationRecord
  # 主动关注关系
  has_many :active_relationships,
           class_name: 'Relationship',
           foreign_key: 'follower_id',
           dependent: :destroy

  has_many :following, through: :active_relationships, source: :followed

  # 被动关注关系(粉丝)
  has_many :passive_relationships,
           class_name: 'Relationship',
           foreign_key: 'followed_id',
           dependent: :destroy

  has_many :followers, through: :passive_relationships, source: :follower

  # 关注用户方法
  def follow(other_user)
    following << other_user unless self == other_user
  end

  # 取消关注
  def unfollow(other_user)
    following.delete(other_user)
  end

  # 检查是否已关注
  def following?(other_user)
    following.include?(other_user)
  end
end

关系模型(app/models/relationship.rb)

class Relationship < ApplicationRecord
  belongs_to :follower, class_name: 'User'
  belongs_to :followed, class_name: 'User'

  # 关键验证
  validates :follower_id, presence: true
  validates :followed_id, presence: true
  validates :follower_id, uniqueness: { scope: :followed_id }  # 防止重复关注
end

路由配置(config/routes.rb)

resources :users do
  member do
    # 获取关注列表
    get :following, :followers

    # 关注/取消关注操作
    post 'follow', to: 'relationships#create'
    delete 'unfollow', to: 'relationships#destroy'
  end
end

# 或使用嵌套资源
resources :relationships, only: [:create, :destroy]

控制器示例(app/controllers/relationships_controller.rb)

class RelationshipsController < ApplicationController
  before_action :authenticate_user!

  def create
    @user = User.find(params[:followed_id])
    current_user.follow(@user)
    respond_to do |format|
      format.html { redirect_to @user }
      format.js   # 支持AJAX
    end
  end

  def destroy
    @user = Relationship.find(params[:id]).followed
    current_user.unfollow(@user)
    respond_to do |format|
      format.html { redirect_to @user }
      format.js
    end
  end
end

3. 最佳实践

  • 数据库优化:为follower_idfollowed_id单独建立索引,并添加复合唯一索引
  • N+1查询解决:在控制器中使用includes(:following)预加载关联数据
  • 安全防护
    • 禁止用户关注自己(在follow方法中添加unless self == other_user
    • 使用dependent: :destroy确保用户删除时关联关系同步清除
  • AJAX支持:通过format.js响应实现无刷新关注/取消操作

4. 常见错误

  • 缺少唯一性验证:导致用户可以重复关注同一个人
  • 索引缺失:当用户关注量大时查询性能急剧下降
  • 路由设计不当:使用非RESTful路由如/follow_user破坏设计规范
  • 未处理自关注:允许用户关注自己导致数据逻辑混乱
  • 回调函数滥用:在关系模型中添加不必要的业务逻辑回调

5. 扩展知识

  • 粉丝系统进阶
    • 添加status字段实现关注请求审批(pending/approved)
    • 使用counter_cache缓存粉丝数和关注数
  • 性能优化
    • 对超大规模用户使用Redis存储关注关系
    • 使用后台作业处理关注通知邮件
  • 测试要点
    • 编写模型测试验证关联关系和业务方法
    • 控制器测试覆盖关注/取消关注的HTTP响应
    • 集成测试模拟用户完整操作流程