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

Jak*_*har 3 model ruby-on-rails self-reference

摔跤我的头脑模型跟随

  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 
Run Code Online (Sandbox Code Playgroud)

Ric*_*nes 6

假设

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

迁移

创建用户表:

class CreateUsers < ActiveRecords::Migrations
  def change
    create_table :users do |t|
      t.text :username
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

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

class CreateContacts < ActiveRecord::Migrations
  def change
    create_table :contacts do |t|
      t.references :owner
      t.references :user
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

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

class CreateGroups < ActiveRecord::Migrations
  def change
    create_table :groups do |t|
      t.references :owner
      t.text :name
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

为联系人和组之间的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
Run Code Online (Sandbox Code Playgroud)

楷模

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

class User
  has_many :contacts, :foreign_key => 'owner_id'
  has_many :groups, :foreign_key => 'owner_id'
end
Run Code Online (Sandbox Code Playgroud)

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

class Contact
  belongs_to :owner, :class_name => 'User'
  belongs_to :user
  has_and_belongs_to_many :groups
end
Run Code Online (Sandbox Code Playgroud)

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

class Group
  belongs_to :owner, :class_name => 'User'
  has_and_belongs_to_many :contacts
end
Run Code Online (Sandbox Code Playgroud)

我们不需要为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
Run Code Online (Sandbox Code Playgroud)

将联系人添加到组

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

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

您的路线可能如下所示:

resources :contact_groups, only: [:create]
Run Code Online (Sandbox Code Playgroud)

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

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

现在,所有你需要的是通过哪些形式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
Run Code Online (Sandbox Code Playgroud)

这将创建一个包含隐藏字段的表单,该字段包含contact_id将显示组名列表的选择字段.当这种形式被提交时,它会通过contact_idgroup_id控制器动作,然后有足够的信息做的事情.