Для ассоциации has_many
<-> belongs_to
вы определяете, что один проект принадлежит (belongs_to
) одному клиенту.Следовательно, у этого клиента есть много (has_many
) проектов.Для того чтобы проект определил, к какому клиенту он принадлежит, он должен иметь столбец client_id
, чтобы он мог его найти.Этот столбец client_id
используется Rails при вызове метода client
, примерно так:
Client.find(project.client_id)
Вот так вы можете найти клиента проекта.Столбец client_id
часто называют внешним ключом , поскольку он является уникальным идентификатором («ключом») в таблице не своего происхождения («чужой»).Boom.
Когда вы звоните наоборот, находя все проекты, которые есть у клиента, то есть client.projects
, Rails делает эквивалент этого:
Project.find_all_by_client_id(client.id)
Это возвращает все Project
записей, которые связаны с конкретным клиентом, на основе поля client_id
в таблице projects
.
С ассоциацией has_and_belongs_to_many
, такой как пример пользователей и групп, выобъявляете, что пользователь has_and_belongs_to_many :groups
.
Теперь, если бы это был просто has_many :groups
, внешний ключ был бы в таблице groups
, или если бы это был belongs_to
, он бы вошел в таблицу users
.Хорошо помнить: внешний ключ всегда помещается в таблицу модели с belongs_to
.
. Вы также объявляете, что группа has_and_belongs_to_many :users
, и поэтому мы сталкиваемся с той же проблемой.Мы не можем объявить ключ в таблице пользователей, потому что он не принадлежит ему (поскольку у пользователя много групп, вам нужно будет сохранить все идентификаторы групп, к которым он принадлежит) или таблицу групп по тем же причинам.
Вот почему для has_and_belongs_to_many
нам нужно создать так называемую таблицу соединений .Эта таблица имеет два и только два поля (оба являются внешними ключами), одно для одной стороны ассоциации и другое для другой.Чтобы создать эту таблицу, мы поместили бы ее в метод миграции self.up
:
create_table :groups_users, :id => false do |t|
t.integer :group_id
t.integer :user_id
end
Здесь необходимо отметить пару вещей:
- Имя таблицы - это два именииз двух ассоциаций в алфавитном порядке.G предшествует U, поэтому имя таблицы равно
groups_users
. - Здесь есть опция
:id
, которая при задании значения false
создает таблицу без первичного ключа.Таблица соединения не нуждается в первичном ключе, потому что ее цель состоит в том, чтобы просто объединить другие таблицы. - Мы храним
group_id
и user_id
как целочисленные поля, как мы это делаем для belongs_to
ассоциация.
В этой таблице будет отслеживаться, какие группы имеют пользователи и наоборот.
Нет необходимости определять дополнительные столбцы для users
или groups
table, потому что таблица соединения получает это под контроль.