Ruby on Rails笔记应用好友功能故障排查与实现求助
修复好友请求问题并完成好友功能
一、清理冗余模型并修正Friendship模型
你当前同时存在Friendship和FriendRequest两个模型,但代码逻辑实际仅依赖Friendship,FriendRequest完全未被使用。先删除FriendRequest模型及对应迁移文件,专注用Friendship实现双向好友请求逻辑:
# models/friendship.rb class Friendship < ApplicationRecord belongs_to :user # 请求发起者 belongs_to :friend, class_name: 'User', foreign_key: 'friend_id' # 请求接收者 enum status: { pending: 'pending', accepted: 'accepted', rejected: 'rejected' } scope :pending_requests, -> { where(status: :pending) } validates :user_id, uniqueness: { scope: :friend_id, message: "已经发送过好友请求" } # 初始化时默认设置请求状态为pending after_initialize :set_default_status, if: :new_record? private def set_default_status self.status ||= :pending end end
用enum管理状态可避免字符串拼写错误,同时自动设置默认状态确保请求创建后处于待处理状态。
二、修正User模型的关联与方法
原User模型中friends方法覆盖了关联定义,且pending_friendships查询逻辑错误,修改如下:
# models/user.rb class User < ApplicationRecord devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable validates :username, presence: true, uniqueness: true has_many :notes has_many :collections scope :private_to_user, ->(user) { where(user_id: user.id) } # 发起的好友请求(当前用户作为请求方) has_many :initiated_friendships, class_name: 'Friendship', foreign_key: 'user_id', dependent: :destroy # 收到的好友请求(当前用户作为接收方) has_many :received_friendships, class_name: 'Friendship', foreign_key: 'friend_id', dependent: :destroy # 已通过的好友列表 has_many :friends, through: :initiated_friendships, source: :friend, -> { where(friendships: { status: :accepted }) } # 获取收到的待处理好友请求 def pending_friend_requests received_friendships.pending_requests end # 判断是否已成为好友 def friend_with?(user) friends.exists?(user.id) end # 判断是否已发送过请求 def sent_friend_request_to?(user) initiated_friendships.exists?(friend_id: user.id) end end
拆分发起/接收请求的关联,避免逻辑混淆,同时补充实用的状态判断方法。
三、修正UsersController的add_friend方法
创建请求时需处理重复请求、已成为好友等异常情况:
# controllers/users_controller.rb class UsersController < ApplicationController def index @users = User.where.not(id: current_user.id) end def friends @user = User.find(params[:id]) @friends = @user.friends end def add_friend @user = User.find(params[:id]) if current_user.sent_friend_request_to?(@user) redirect_to users_path, alert: '已经发送过好友请求' elsif current_user.friend_with?(@user) redirect_to users_path, alert: '你们已经是好友' else current_user.initiated_friendships.create(friend: @user) redirect_to users_path, notice: '好友请求已发送' end end end
四、修正FriendshipsController逻辑
原index方法错误查询了当前用户发起的请求,需改为查询收到的请求,同时补充拒绝请求、撤回请求的逻辑:
# controllers/friendships_controller.rb class FriendshipsController < ApplicationController def index @received_requests = current_user.pending_friend_requests @sent_requests = current_user.initiated_friendships.pending_requests end # 接受好友请求 def update friendship = current_user.received_friendships.find(params[:id]) friendship.accepted! # 创建反向关联确保双向好友关系 current_user.initiated_friendships.find_or_create_by(friend: friendship.user, status: :accepted) redirect_to friendships_path, notice: '好友请求已接受' end # 拒绝好友请求 def destroy friendship = current_user.received_friendships.find(params[:id]) friendship.rejected! redirect_to friendships_path, notice: '好友请求已拒绝' end # 撤回已发送的请求 def cancel_request friendship = current_user.initiated_friendships.find(params[:id]) friendship.destroy redirect_to friendships_path, notice: '好友请求已撤回' end end
五、修正请求视图文件
区分收到的请求和已发送的请求,添加拒绝、撤回按钮:
# friendships/index.html.erb <h1>好友请求</h1> <h2>收到的请求</h2> <ul> <% @received_requests.each do |friendship| %> <li> <%= friendship.user.username %> <%= link_to "接受", friendship_path(friendship), method: :put %> <%= link_to "拒绝", friendship_path(friendship), method: :delete %> </li> <% end %> </ul> <h2>已发送的请求</h2> <ul> <% @sent_requests.each do |friendship| %> <li> <%= friendship.friend.username %> <%= link_to "撤回请求", cancel_request_friendship_path(friendship), method: :delete %> </li> <% end %> </ul>
六、配置路由
在config/routes.rb中添加对应路由:
Rails.application.routes.draw do devise_for :users resources :users do member do post :add_friend end get :friends end resources :friendships do member do delete :cancel_request end end root 'users#index' end
七、数据库迁移
确保Friendship表包含status字段,若没有则生成迁移:
rails generate migration AddStatusToFriendships status:string rails db:migrate
可修改迁移文件设置默认值:
class AddStatusToFriendships < ActiveRecord::Migration[7.0] def change add_column :friendships, :status, :string, default: 'pending', null: false end end
八、用户列表视图添加按钮
在users/index.html.erb中根据状态显示不同按钮:
<h1>所有用户</h1> <ul> <% @users.each do |user| %> <li> <%= user.username %> <% if current_user.friend_with?(user) %> <span>已成为好友</span> <%= link_to "查看主页", user_friends_path(user) %> <% elsif current_user.sent_friend_request_to?(user) %> <span>请求已发送</span> <% else %> <%= link_to "添加好友", add_friend_user_path(user), method: :post %> <% end %> </li> <% end %> </ul>
完成以上修改后,好友请求可正常发送,接收方能在请求页面处理请求,好友列表可正确显示,点击好友可进入其主页查看笔记与收藏夹。
内容的提问来源于stack exchange,提问作者daniel
相关产品推荐
相关产品推荐

