Как бы вы смоделировали список контактов с собственной ссылкой и категорией?
Борьба с моей головой, чтобы следовать модели
- У пользователя много категорий контактов (семья / друзья)
- Одна категория контактов имеет много контактов
- Один контакт может быть в одной или нескольких категориях контактов.
Я заканчиваю тем, что следую, но я все еще верю, что должно быть лучшее решение.
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
2 ответа
Предположения
- Это система для многих пользователей, а не только для одного, поэтому вам необходимо указать владельца в записях контактов и групп с помощью внешнего ключа.
- Контакт может принадлежать нескольким группам, а группа имеет несколько контактов, поэтому это отношение 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, поскольку мы не будем обращаться к ней напрямую, а вместо этого будем обращаться к ней только через контакт или группу.
Результаты
Это позволит вам делать что-то вроде следующего:
@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_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
Теперь все, что вам нужно, это формы, которые проходят contact_id
а также group_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_id
а также group_id
к действию контроллера, который затем имеет достаточно информации, чтобы сделать свое дело.
Вы можете использовать has_many: через Ассоциацию
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
это будет работать