用户关注功能中的关联关系

关于多对多的关联关系,其实并不简单,最典型的例子就是类似 Twitter 这样的关注功能。

一个用户可以被很多个用户关注,同时,也关注很多个用户。这很明显就是多对多的关系。

一般的多对多关系都是发生在不同的两个 model 之间,比如说 Group 和 User,建立关联的方法是,通过一个中间表格,比如说 GroupRelationship,这个中间表格记录了 group_iduser_id 的一一对应关系,再通过 has_many ... through ... 来建立关联关系。

关注这个动作是发生在用户与用户之间的,在 model 层级来看,关注和被关注,都是发生在同一个 model 内的动作。这要怎样来实现呢?

同样,也需要建立一个中间表格,这个中间表格需要建立用户与用户之间的一一对应关系,也就是关注者和被关注者之间的对应关系。显然就不能定义两个 user_id 作为栏位,可以命名为 follower_idfollowing_id

class CreateRelationships < ActiveRecord::Migration[5.0]
  def change
    create_table :relationships do |t|
      t.integer :follower_id
      t.integer :following_id

      t.timestamps
    end
    add_index :relationships, :follower_id
    add_index :relationships, :following_id
    add_index :relationships, [:follower_id, :following_id], unique: true
  end
end

回想 Group 和 User 之间建立多对多关系的时候,对于 Group 要 has_many 关系表格和 User ,而 User 要 has_many 关系表格和 Group。

class Group < ApplicationRecord
  has_many :group_relationship
  has_many :users, through: :group_relationship, source: :user_id
end
class User < ApplicationRecord
  has_many :group_relationship
  has_many :groups, through: :group_relationship, source: :group_id
end

而现在,这些关联关系的定义全部要发生在 User 这一个 Model 里,这就需要重命名属性,还有详细定义关联关系的各个参数。

class User < ApplicationRecord
  has_many :microposts, dependent: :destroy
  has_many :active_relationships,  class_name:  "Relationship",
                                   foreign_key: "follower_id",
                                   dependent:   :destroy
  has_many :passive_relationships, class_name:  "Relationship",
                                   foreign_key: "following_id",
                                   dependent:   :destroy
  has_many :following, through: :active_relationships,  source: :following
  has_many :followers, through: :passive_relationships, source: :follower
  .
  .
  .
end

这里面对于中间表格,分别命名为 active_relationshipspassive_relationships ,对应的是「作为关注者的关系表格」和「作为被关注者的关系表格」。这两张表格其实都是来源于同一张表格,也就是 class_name: "Relationship" ,但是对应的外键 foreign_key 是不一样的。

对照着 Group 和 User 的关联例子,再去审视 User 和 User 本身的关联关系,会理解得更加清晰。在用户关注功能的实现里,User 这一个 model 其实充当了关联关系中的两个角色。

· rails