ActiveRecord, has_many: through i Skojarzenia polimorficzne


117

Ludzie,

Chcę się upewnić, że dobrze to rozumiem. I proszę zignoruj ​​tutaj przypadek dziedziczenia (SentientBeing), próbując zamiast tego skupić się na modelach polimorficznych w has_many: poprzez relacje. To powiedziawszy, rozważ następujące ...

class Widget < ActiveRecord::Base
  has_many :widget_groupings

  has_many :people, :through => :widget_groupings, :source => :person, :conditions => "widget_groupings.grouper_type = 'Person'"
  has_many :aliens, :through => :widget_groupings, :source => :alien, :conditions => "video_groupings.grouper_type = 'Alien'"
end

class Person < ActiveRecord::Base
  has_many :widget_groupings, :as => grouper
  has_many :widgets, :through => :widget_groupings
end

class Alien < ActiveRecord::Base
  has_many :widget_groupings, :as => grouper
  has_many :widgets, :through => :widget_groupings  
end

class WidgetGrouping < ActiveRecord::Base
  belongs_to :widget
  belongs_to :grouper, :polymorphic => true
end

W idealnym świecie chciałbym, mając widżet i osobę, zrobić coś takiego:

widget.people << my_person

Jednak kiedy to robię, zauważyłem, że 'typ' 'groupera' jest zawsze pusty w widget_groupings. Jeśli jednak dojdę do czegoś takiego:

widget.widget_groupings << WidgetGrouping.new({:widget => self, :person => my_person}) 

Wtedy wszystko działa tak, jak bym się normalnie spodziewał. Nie sądzę, żebym kiedykolwiek widział, jak to się dzieje w przypadku skojarzeń niepolimorficznych i po prostu chciałem wiedzieć, czy było to coś specyficznego dla tego przypadku użycia, czy też potencjalnie wpatruję się w błąd.

Dzięki za pomoc!

Odpowiedzi:


162

W Railsach 3.1.1 występuje znany problem, który przerywa tę funkcjonalność. Jeśli masz ten problem, spróbuj najpierw zaktualizować, został on naprawiony w wersji 3.1.2

Jesteś tak blisko. Problem polega na tym, że nadużywasz opcji: source. : źródło powinno wskazywać na polimorficzną zależność should_to. Następnie wszystko, co musisz zrobić, to określić: typ_źródła dla relacji, którą próbujesz zdefiniować.

Ta poprawka do modelu widżetu powinna umożliwić Ci zrobienie dokładnie tego, czego szukasz.

class Widget < ActiveRecord::Base
  has_many :widget_groupings

  has_many :people, :through => :widget_groupings, :source => :grouper, :source_type => 'Person'
  has_many :aliens, :through => :widget_groupings, :source => :grouper, :source_type => 'Alien'
end

O mój Boże, to jest tak boleśnie oczywiste, że nie mogę uwierzyć, że przeszedłem tuż nad tym. Dzięki EmFi!
— Cory

Nie ma problemu, myślę, że przez około jeden dzień męczyłem się nad tym, jak to zrobić, gdy pierwszy raz go spotkałem. Nie pomogło, że była to jedna z pierwszych rzeczy, które próbowałem zrobić w Railsach, które nie wymagały podążania za samouczkiem / książką.
— EmFi

1
Jak wskazuje scotkf, w ActiveRecord 3.1.1 występuje regresja, która blokuje to zachowanie. Aktualizacja do wersji 3.1.2 umożliwi działanie tego rozwiązania.
— EmFi

6
To samo, o czym wspomniał @Shtirlic. Czy istnieje sposób, aby nie określać source_type, więc masz mieszany zestaw wyników? Gdyby ktoś to rozwiązał, chciałby wiedzieć, jak to zrobić.
— Damon Aw,

3
Nadal działa od Railsów 4.2.0. Czy jest jednak jakikolwiek sposób na osiągnięcie tego w dzisiejszych czasach bez source_type i dwóch oddzielnych skojarzeń?
— Emeka

3

Jak wspomniano powyżej, nie działa to z railsami 3.1.1 z powodu błędu w: source, ale zostało to naprawione w Railsach 3.1.2


-4

ma wiele: na wskroś i polimorficzne nie działają razem. Jeśli spróbujesz uzyskać do nich bezpośredni dostęp, powinien wyświetlić błąd. Jeśli się nie mylę, musisz ręcznie napisać widget.people i procedurę push.

Nie sądzę, żeby to był błąd, to po prostu coś, czego jeszcze nie zaimplementowano. Wyobrażam sobie, że widzimy to w funkcji, ponieważ każdy ma przypadek, w którym mógłby go użyć.


6
Pracują razem. Na przykład: has_many: subscriptions,: as =>: subscribable has_many: subscribers
— ,:

W najbliższej przyszłości podam w osobnym poście przykład mojego błędnego kodu :) Oszczędziłoby mi to wielu kłopotów z wymyśleniem, jak obejść ten błąd.
— cgr
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.