Próbuję zrozumieć, czym has_many :through
jest i kiedy (i jak) tego używać. Jednak nie rozumiem. Czytam Beginning Rails 3 i próbowałem googlować, ale nie jestem w stanie tego zrozumieć.
Próbuję zrozumieć, czym has_many :through
jest i kiedy (i jak) tego używać. Jednak nie rozumiem. Czytam Beginning Rails 3 i próbowałem googlować, ale nie jestem w stanie tego zrozumieć.
Odpowiedzi:
Powiedzmy, że masz dwa modele: User
i Group
.
Jeśli chciałbyś, aby użytkownicy należeli do grup, możesz zrobić coś takiego:
class Group < ActiveRecord::Base
has_many :users
end
class User < ActiveRecord::Base
belongs_to :group
end
A co by było, gdybyś chciał śledzić dodatkowe metadane wokół powiązania? Na przykład, kiedy użytkownik dołączył do grupy, a może jaka jest rola użytkownika w grupie?
Tutaj tworzysz asocjację jako obiekt pierwszej klasy:
class GroupMembership < ActiveRecord::Base
belongs_to :user
belongs_to :group
# has attributes for date_joined and role
end
Wprowadza to nową tabelę i eliminuje group_id
kolumnę z tabeli użytkownika.
Problem z tym kodem polega na tym, że musiałbyś zaktualizować każde inne miejsce, w którym używasz klasy użytkownika, i zmienić ją:
user.groups.first.name
# becomes
user.group_memberships.first.group.name
Ten typ kodu jest do bani i sprawia, że wprowadzanie takich zmian jest bolesne.
has_many :through
daje to, co najlepsze z obu światów:
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
Teraz możesz traktować to jak normalne has_many
, ale skorzystaj z modelu asocjacyjnego, gdy go potrzebujesz.
Pamiętaj, że możesz to również zrobić za pomocą has_one
.
Edycja: ułatwianie dodawania użytkownika do grupy
def add_group(group, role = "member")
self.group_associations.build(:group => group, :role => role)
end
user.groups << group
? A może wszystkim zajmuje się to stowarzyszenie?
Powiedzmy, że masz te modele:
Car
Engine
Piston
Samochód has_one :engine
Silnik belongs_to :car
Silnik has_many :pistons
Tłokbelongs_to :engine
Samochód has_many :pistons, through: :engine
tłokowyhas_one :car, through: :engine
Zasadniczo delegujesz relację modelu do innego modelu, więc zamiast dzwonić car.engine.pistons
, możesz to zrobićcar.pistons
has_many :through
i has_and_belongs_to_many
relacje funkcjonują za pośrednictwem tabeli łączenia , która jest tabelą pośrednią reprezentującą relacje między innymi tabelami. W przeciwieństwie do zapytania JOIN dane są w rzeczywistości przechowywane w tabeli.
Dzięki temu has_and_belongs_to_many
nie potrzebujesz klucza podstawowego i uzyskujesz dostęp do rekordów za pośrednictwem relacji ActiveRecord, a nie za pośrednictwem modelu ActiveRecord. Zwykle używasz HABTM, gdy chcesz połączyć dwa modele relacją wiele do wielu.
Używasz has_many :through
relacji, gdy chcesz współdziałać z tabelą złączeń jako modelem Rails, wraz z kluczami podstawowymi i możliwością dodawania niestandardowych kolumn do połączonych danych. To ostatnie jest szczególnie ważne w przypadku danych, które są istotne dla połączonych wierszy, ale tak naprawdę nie należą do powiązanych modeli - na przykład przechowywanie obliczonej wartości pochodzącej z pól w połączonym wierszu.
W Przewodniku po stowarzyszeniach Active Record rekomendacja brzmi:
Najprostsza praktyczna zasada jest taka, że jeśli chcesz pracować z modelem relacji jako niezależny byt, powinieneś skonfigurować relację has_many: poprzez relację. Jeśli nie musisz nic robić z modelem relacji, prostsze może być skonfigurowanie relacji has_and_belongs_to_many (chociaż musisz pamiętać o utworzeniu tabeli łączącej w bazie danych).
Powinieneś użyć has_many: through, jeśli potrzebujesz walidacji, wywołań zwrotnych lub dodatkowych atrybutów w modelu łączenia.
user
modelu, aby dodać grupę. Coś jak zmiana, którą właśnie zrobiłem. Mam nadzieję że to pomoże.