您正在寻找的是 has_and_belongs_to_many 关系,但与同一个表,有点像 Many-to-many relationship with the same model in rails? 详细描述的那样。但是,由于您希望关系是双向的(“我的朋友也是我的朋友”),您有两种选择:
-
使用单个连接表,其中每一行链接两个 user_id,但为每个友谊插入两行。
# no need for extra columns on User
class User < ActiveRecord::Base
has_many :friendships
has_many :friends, through: :friendships
end
# t.belongs_to :user; t.belongs_to :friend
class Friendship < ActiveRecord::Base
belongs_to :user
belongs_to :friend, class_name: "User"
end
u1 = User.create!
u2 = User.create!
u3 = User.create!
# make users 1 and 2 friends
u1.friendships.create(friend: u2)
u2.friendships.create(friend: u1)
# make users 2 and 3 friends
u2.friendships.create(friend: u3)
u3.friendships.create(friend: u2)
# and now, u1.friends returns [u1],
# u2.friends returns [u1, u3] and
# u3.friends returns [u2].
-
使用单一记录,但很容易找到您的朋友:
# no need for extra columns on User
class User < ActiveRecord::Base
has_many :friendships_as_a, class_name: "Friendship", foreign_key: :user_a_id
has_many :friendships_as_b, class_name: "Friendship", foreign_key: :user_b_id
def friends
User.where(id: friendships_as_a.pluck(:user_b_id) + friendships_as_b.pluck(:user_a_id))
end
end
# t.belongs_to :user_a; t.belongs_to :user_b
class Friendship < ActiveRecord::Base
belongs_to :user_a, class_name: "User"
belongs_to :user_b, class_name: "User"
end
这不是最干净的方法,但我想你会发现当这样设置时并没有特别干净的方法(使用非规范化表)。选项 1 是一个更安全的选择。您还可以使用 SQL 视图通过自动为每个友谊生成镜像条目来达到中间立场。
编辑:API 中的迁移和使用
根据下面 OP 的评论,要完全使用选项 1,您需要执行以下操作:
rails g migration CreateFriendships
将该文件编辑为如下所示:
class CreateFriendships < ActiveRecord::Migration
create_table :friendships do |t|
t.belongs_to :user
t.belongs_to :friend
t.timestamps
end
end
创建友谊模型:
class Friendship < ActiveRecord::Base
belongs_to :user
belongs_to :friend, class_name: "User"
end
然后在您的用户模型上:
class User < ActiveRecord::Base
# ...
has_many :friendships
has_many :friends, through: :friendships, class_name: 'User'
# ...
end
在你的 API 中,说一个新的 FriendshipsController:
class FriendshipsController < ApplicationController
def create
friend = User.find(params[:friend_id])
User.transaction do # ensure both steps happen, or neither happen
Friendship.create!(user: current_user, friend: friend)
Friendship.create!(user: friend, friend: current_user)
end
end
end
您的路线看起来像(config/routes.rb):
resource :friendships, only: [:create]
请求如下所示:
POST /friendships?friend_id=42
然后,您可以随时参考current_user.friends 查找用户的好友。