侧边栏壁纸
博主头像
colo

欲买桂花同载酒

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

实现用户关注功能与粉丝列表展示

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

题目

实现用户关注功能与粉丝列表展示

信息

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

考点

模型关联设计, ActiveRecord查询优化, 数据库索引应用

快速回答

实现用户关注功能的核心要点:

  • 使用has_many :through建立自连接多对多关系
  • 创建FollowRelationship连接模型记录关注状态
  • 添加数据库唯一索引防止重复关注
  • 使用counter_cache优化粉丝数统计
  • N+1查询优化通过includes预加载关联数据
## 解析

原理说明

用户关注功能本质是自引用多对多关系:一个用户可关注多个其他用户(following),同时被多个用户关注(followers)。需要中间表(follow_relationships)存储关联关系,通过ActiveRecord的has_many :through实现模型关联。

代码实现

1. 数据迁移文件

# db/migrate/xxx_create_follow_relationships.rb
class CreateFollowRelationships < ActiveRecord::Migration[7.0]
  def change
    create_table :follow_relationships do |t|
      t.references :follower, foreign_key: { to_table: :users }
      t.references :followed, foreign_key: { to_table: :users }
      t.timestamps
    end

    # 关键优化:添加复合唯一索引和单字段索引
    add_index :follow_relationships, [:follower_id, :followed_id], unique: true
    add_index :follow_relationships, :followed_id  # 用于粉丝列表查询
  end
end

2. 模型关联设计

# app/models/user.rb
class User < ApplicationRecord
  # 关注他人关系
  has_many :active_relationships, 
           class_name: 'FollowRelationship',
           foreign_key: 'follower_id',
           dependent: :destroy

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

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

  has_many :followers, 
           through: :passive_relationships, 
           source: :follower,
           counter_cache: :followers_count  # 粉丝数缓存

  # 关注/取消关注方法
  def follow(other_user)
    active_relationships.create(followed_id: other_user.id)
  end

  def unfollow(other_user)
    active_relationships.find_by(followed_id: other_user.id)&.destroy
  end

  def following?(other_user)
    following.include?(other_user)
  end
end

# app/models/follow_relationship.rb
class FollowRelationship < ApplicationRecord
  belongs_to :follower, class_name: 'User'
  belongs_to :followed, class_name: 'User'

  # 数据验证
  validates :follower_id, uniqueness: { scope: :followed_id }
  validate :cannot_follow_self

  private
  def cannot_follow_self
    errors.add(:base, 'Cannot follow yourself') if follower_id == followed_id
  end
end

最佳实践

  • 索引优化:复合唯一索引防止重复关注,单字段索引加速粉丝列表查询
  • counter_cache:在users表添加followers_count字段,避免COUNT查询性能问题
  • N+1解决方案:控制器中使用includes预加载关联数据

控制器优化示例

# app/controllers/users_controller.rb
def followers
  @user = User.includes(followers: :profile).find(params[:id])
  # 渲染粉丝列表视图
end

常见错误

  • 缺少唯一索引:导致数据库层可能产生重复关注记录
  • N+1查询问题:列表页未预加载关联数据导致性能瓶颈
  • 未处理自关注:允许用户关注自己导致数据逻辑错误
  • 事务缺失:关注/取消关注操作未包裹事务,可能产生数据不一致

扩展知识

  • 异步处理:使用ActiveJob发送关注通知邮件
  • 高级查询:使用SQL的EXISTS优化互关检测:
    User.where(id: other_user.id).exists?(id: following_ids)
  • 安全考虑:控制器中验证当前用户权限,防止越权操作
  • 测试要点:验证关注/取消关注的边界条件(如重复操作、自关注等)