Я пытаюсь понять, что такое has_many :through
и когда его использовать (и как). Однако я не понимаю. Я читаю "Начало Rails 3", и я попробовал Google, но я не могу понять.
Когда нужно использовать отношение "has_many: through" в Rails?
Ответ 1
Скажем, у вас две модели: 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
Ответ 2
Скажите, что у вас есть эти модели:
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
Ответ 3
Таблицы соединений ActiveRecord
has_many :through
и has_and_belongs_to_many
связаны через таблицу соединений, которая представляет собой промежуточную таблицу, которая представляет взаимосвязь между другими таблицами. В отличие от запроса JOIN данные фактически хранятся в таблице.
Практические отличия
С has_and_belongs_to_many
вам не нужен первичный ключ, и вы получаете доступ к записям через отношения ActiveRecord, а не через модель ActiveRecord. Обычно вы используете HABTM, если хотите связать две модели с отношением "многие-ко-многим".
Вы используете связь has_many :through
, когда хотите взаимодействовать с таблицей соединений как модель Rails, в комплекте с первичными ключами и возможность добавлять собственные столбцы к объединенным данным. Последнее особенно важно для данных, относящихся к объединенным строкам, но на самом деле не относится к связанным моделям, например, сохраняя вычисленное значение, полученное из полей в объединенной строке.
См. также
В Руководство для активных ассоциаций записей, рекомендация гласит:
Самое простое правило состоит в том, что вы должны настроить has_many: через отношения, если вам нужно работать с моделью отношений как независимой сущности. Если вам не нужно что-либо делать с моделью отношений, может быть проще установить отношения has_and_belongs_to_many (хотя вам нужно помнить о создании таблицы соединения в базе данных).
Вы должны использовать has_many: через, если вам нужны проверки, обратные вызовы или дополнительные атрибуты в модели объединения.
Ответ 4
Я предлагаю пройти через
http://guides.rubyonrails.org/association_basics.html
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
Это официальная документация по рельсам, и они хорошо документированы.
также http://apidock.com/rails/ActiveRecord/Associations/ClassMethods/has_many.
Существует также скринкаст ryan bates здесь http://railscasts.com/episodes/47-two-many-to-many
Ответ 5
Прочитайте этот раздел в Rails Tutorial и has_many: через раздел рельсов руководство.
В этих статьях вам следует объяснить, когда следует использовать has_many :through
.