Когда следует использовать отношение «has_many: through» в Rails?

Я пытаюсь понять, что такое has_many :through и когда его использовать (и как). Однако я этого не понимаю. Я читаю Beginning Rails 3 и пробовал поискать в Google, но не могу понять.

108 голосов | спросил LuckyLuke 22 J000000Sunday12 2012, 18:05:43

3 ответа


0

Допустим, у вас есть две модели: User и Group.

Если вы хотите, чтобы пользователи принадлежали к группам, вы можете сделать что-то вроде этого:

class Group < ActiveRecord::Base
  has_many :users
end

class User < ActiveRecord::Base
  belongs_to :group
end

Что если вы хотите отслеживать дополнительные метаданные вокруг ассоциации? Например, когда пользователь присоединился к группе, или, возможно, какова роль пользователя в группе?

Здесь вы делаете ассоциацию объектом первого класса:

class GroupMembership < ActiveRecord::Base
  belongs_to :user
  belongs_to :group

  # has attributes for date_joined and role
end

Это вводит новую таблицу и удаляет столбец group_id из таблицы пользователя.

Проблема с этим кодом в том, что вам придется обновлять каждый раз, когда вы используете пользовательский класс, и изменять его:

user.groups.first.name

# becomes

user.group_memberships.first.group.name

Этот тип кода отстой, и это делает введение таких изменений болезненным.

has_many :through дает вам лучшее из обоих миров:

class User < ActiveRecord::Base
  has_many :groups, :through => :group_memberships  # Edit :needs to be plural same as the has_many relationship   
  has_many :group_memberships
end

Теперь вы можете обращаться с ним как с обычным has_many, но получите преимущество от модели ассоциации, когда вам это нужно.

Обратите внимание, что вы также можете сделать это с помощью has_one.

Изменить. Упрощение добавления пользователя в группу

def add_group(group, role = "member")
  self.group_associations.build(:group => group, :role => role)
end
ответил Ben Scheirman 22 J000000Sunday12 2012, 18:47:22
0

Скажем, у вас есть эти модели:

Car
Engine
Piston

Автомобиль has_one :engine
Двигатель belongs_to :car
Двигатель has_many :pistons
Поршень belongs_to :engine

Автомобиль has_many :pistons, through: :engine
Поршень has_one :car, through: :engine

По сути, вы делегируете отношение модели к другой модели, поэтому вместо вызова car.engine.pistons вы можете просто выполнить car.pistons

ответил cpuguy83 22 J000000Sunday12 2012, 18:44:41
0

ActiveRecord Соединение таблиц

Функция связи

has_many :through и has_and_belongs_to_many через таблицу соединений , которая является промежуточной таблицей, представляющей отношения между другими таблицами. В отличие от запроса JOIN, данные на самом деле хранятся в таблице.

Практические различия

С has_and_belongs_to_many вам не нужен первичный ключ, и вы получаете доступ к записям через отношения ActiveRecord, а не через модель ActiveRecord , Обычно вы используете HABTM, когда хотите связать две модели с отношением «многие ко многим».

Вы используете отношение has_many :through, когда хотите взаимодействовать с таблицей соединений в качестве модели Rails, дополненной первичными ключами и возможностью добавить пользовательские столбцы к объединенным данным. Последнее особенно важно для данных, которые относятся к объединенным строкам, но на самом деле не относятся к связанным моделям - например, для хранения вычисленного значения, полученного из полей в объединенной строке.

Смотрите также

В Руководстве по ассоциациям активных записей рекомендация гласит:

  

Самое простое практическое правило - установить отношения has_many: through, если вам нужно работать с моделью отношений как с независимой сущностью. Если вам не нужно ничего делать с моделью отношений, может быть проще установить отношение has_and_belongs_to_many (хотя вам нужно помнить о создании объединяющей таблицы в базе данных).

     

Вы должны использовать has_many: through, если вам нужны проверки, обратные вызовы или дополнительные атрибуты в модели соединения.

ответил Todd A. Jacobs 22 J000000Sunday12 2012, 19:20:01

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132