模型设计:用户有朋友是用户

我想在追求这种关联之前确保我的方法是正确的。 实施听起来太复杂了,所以我认为我的计划肯定有问题。 我正在使用结构化(SQL)数据存储,符合rails存储约定。 我所拥有的是用户模型,它在Schema中有一个电子邮件地址, password_digest和名称。

 class User < ActiveRecord::Base has_many :posts end 

我想对一个朋友集合实现一个has_many关联,这样用户就可以belong_to用户(作为朋友)。 我希望能够让User.last.friends.last在正确构建和填充时返回User对象。

我相信我可以为这个协会创建一个模型,如:

 Class Friend < ActiveRecord::Base belongs_to :user belongs_to :friendlies, class: 'User' end Class User < ActiveRecord::Base has_many :posts has_many :friends has_many :friendly, class: 'Friend' end 

但我认为这将要求我使用User.last.friends.last.user添加模型和查询。所以我在想的是这是一个has_and_belongs_to_many关系。 我可以逃脱以下(或类似的东西):

 class User < ActiveRecord::Base has_and_belongs_to_many :friends, class: 'User' end 

我发现了这个 :

 class User < ActiveRecord::Base has_many :user_friendships has_many :friends, through: :user_friendships class UserFriendship < ActiveRecord::Base belongs_to :user belongs_to :friend, class_name: 'User', foreign_key: 'friend_id' 

而这 (自称“标准”):

 has_many :friendships, :dependent => :destroy has_many :friends, :through => :friendships, :dependent => :destroy has_many :inverse_friendships, :class_name => "Friendship", :foreign_key => "friend_id", :dependent => :destroy has_many :inverse_friends, :through => :inverse_friendships, :source => :user, :dependent => :destroy 

我假设需要一个Friendship模型。 我觉得我不需要友谊模特。 我认为class UserFriendship方法看起来正确,但它需要一个额外的模型。 现在问题:

  1. 我可以与将用户与用户的朋友关联的表进行has_and_belongs_to_many关系,而不会产生额外的模型吗?

  2. 是否有额外的模型“万一”以后会出现额外的要求?

您正在寻找的是一种称为self referential join东西,这意味着您可以使用不同的关联引用相同的model

 #app/models/user.rb class User < ActiveRecord::Base has_and_belongs_to_many :friendships, class_name: "User", join_table: :friendships, foreign_key: :user_id, association_foreign_key: :friend_user_id end 

您必须创建一个habtm连接表以获得引用:

 $ rails g migration CreateFriendshipsTable #db/migrate/create_friendships_table____.rb class CreateFriendShipsTable < ActiveRecord::Migration def change create_table :friendships, id: false do |t| t.integer :user_id t.integer :friend_user_id end add_index(:friendships, [:user_id, :friend_user_id], :unique => true) add_index(:friendships, [:friend_user_id, :user_id], :unique => true) end end $ rake db:migrate 

这里有一个很好的参考: Rails:与has_and_belongs_to_many的自联接方案?


是否有额外的模型“万一”以后会出现额外的要求?

只有当你知道你将拥有额外的属性时。 如果没有,你可以随心所欲地逃脱这个问题。

你可以试试这个

–friendship.rb

 class Friendship < ApplicationRecord belongs_to :user belongs_to :friend, :class_name => 'User' end 

–user.rb

 class User < ApplicationRecord has_many :friendships has_many :friends, through: :friendships end 

--db migrate xxxx_create_friendship.rb

 class CreateFriendships < ActiveRecord::Migration[5.0] def change create_table :friendships do |t| t.belongs_to :user t.belongs_to :friend, class: 'User' t.timestamps end end end 

Rich的答案是一个很好的资源。 我设法通过遵循这个惯例颠覆了几个步骤:

 # app/model/user.rb has_and_belongs_to_many :friends, class_name: "User", join_table: :friends_users, foreign_key: :user_id, association_foreign_key: :friend_id 

这种迁移就足够了(不修改生成的代码):

 rails g migration CreateFriendlyJoinTable users friends 

使用rails generate migration -h找到了JoinTable语法