您如何使用自引用和类别对联系人列表进行建模?

摔跤我的头脑模型跟随

  1. 用户有很多联系人类别(家人/朋友)
  2. 一个联系人类别有很多联系人
  3. 一个联系人可以是一个或多个联系人类别。

我最终会跟随,但我仍然相信,必须有更好的解决方案。

class User < ActiveRecord::Base has_many :contact_groups def get_all_contacts self.contact_groups.each do |group| contacts << group.users end end class ContactGroup < ActiveRecord::Base has_and_belongs_to_many :users end 

假设

  • 这是一个适用于许多用户的系统,而不仅仅是一个系统,因此您需要使用外键在联系人和组记录上指定所有者。
  • 联系人可以属于多个组,组可以有多个联系人,因此这是一个has_and_belongs_to_many关系。

迁移

创建用户表:

 class CreateUsers < ActiveRecords::Migrations def change create_table :users do |t| t.text :username end end end 

创建联系人表。 具有联系人用户的外键以及联系人所引用的用户。

 class CreateContacts < ActiveRecord::Migrations def change create_table :contacts do |t| t.references :owner t.references :user end end end 

创建组表。 还有该组所属的用户的外键。

 class CreateGroups < ActiveRecord::Migrations def change create_table :groups do |t| t.references :owner t.text :name end end end 

为联系人和组之间的has_and_belongs_to_many关系创建表。 有两个外键; 一个用于联系,另一个用于组。

 class CreateContactsGroups < ActiveRecord::Migrations def change create_table :contacts_groups do |t| t.references :contact t.references :group end end end 

楷模

用户模型。 用户有许多联系人,联系人表上与用户联系的外键是'owner_id'列。 群组也是如此。

 class User has_many :contacts, :foreign_key => 'owner_id' has_many :groups, :foreign_key => 'owner_id' end 

联系模式。 联系人属于所有者,我们使用“用户”模型作为所有者关系。 此外,联系人指的是另一个用户(或属于Rails用语,在这种情况下有点令人困惑),但是:用户匹配模型的名称,因此我们不需要像以下那样指定:所有者。 最后,拥有并属于与群体的许多关系。

 class Contact belongs_to :owner, :class_name => 'User' belongs_to :user has_and_belongs_to_many :groups end 

集团模式。 一个组属于所有者,拥有并属于许多联系人。

 class Group belongs_to :owner, :class_name => 'User' has_and_belongs_to_many :contacts end 

我们不需要为contacts_groups表创建一个Model,因为我们不会直接访问它,而只会通过Contact或Group访问它。

结果

这将允许您执行以下操作:

 @user.contacts # all of the user's contacts @user.groups # all of the user's groups @user.groups.find(id).contacts # all the contacts in a group @user.contacts.find(id).groups # all of the groups that a contact belongs to 

将联系人添加到组

这是对@benrmatthews评论的回应,询问将联系人添加到组的视图。

实际上有很多不同的方法可以实现这一点,但一般的想法是你需要将Contact id和Group id传递给一个控制器动作,然后在contact_groups表中创建一个条目,表明已经添加了联系人到小组。

您的路线可能如下所示:

 resources :contact_groups, only: [:create] 

然后你将有一个看起来像这样的控制器:

 class ContactGroupsController < ApplicationController def create @contact = Contact.find(params[:contact_id]) @group = Group.find(params[:group_id]) @contact.groups << @group end end 

现在您只需group_id contact_idgroup_id传递给控制器​​操作的表单。 这是什么样子:

 # This is for adding the contact to a group form_tag contact_groups_path do hidden_field_tag :contact_id, @contact.id select_tag :group_id, options_from_collection_for_select(Group.all, :id, :name) submit_tag "Add to Group" end 

这将创建一个包含隐藏字段的表单,其中包含contact_id和一个将显示组名列表的选择字段。 提交此表单时,它会将contact_idgroup_id传递给控制器​​操作,然后控制器操作有足够的信息来执行此操作。

你可以使用has_many:通过Association

 class User has_many :contacts has_many :contact_groups, :through => :contacts end class Contact belongs_to :user has_many :contact_groups end class ContactGroup belongs_to :contacts end 

这会奏效。