ActiveRecord, has_many: through und Polymorphic Associations


117

Leute,

Ich möchte sicherstellen, dass ich das richtig verstehe. Und bitte ignorieren Sie den Fall der Vererbung hier (SentientBeing) und versuchen Sie stattdessen, sich auf polymorphe Modelle in has_many zu konzentrieren: durch Beziehungen. Beachten Sie jedoch Folgendes ...

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

In einer perfekten Welt möchte ich mit einem Widget und einer Person etwas tun wie:

widget.people << my_person

Dabei habe ich jedoch festgestellt, dass der 'Typ' des 'Grouper' in widget_groupings immer null ist. Allerdings, wenn ich zu so etwas wie folgendem komme:

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

Dann funktioniert alles so, wie ich es normalerweise erwartet hätte. Ich glaube nicht, dass ich dies jemals bei nicht polymorphen Assoziationen gesehen habe und wollte nur wissen, ob dies etwas Spezielles für diesen Anwendungsfall ist oder ob ich möglicherweise auf einen Fehler starre.

Vielen Dank für jede Hilfe!

Antworten:


162

Es ist ein Problem mit Rails 3.1.1 bekannt, das diese Funktionalität beeinträchtigt. Wenn Sie dieses Problem zuerst haben, versuchen Sie es mit einem Upgrade. Es wurde in 3.1.2 behoben

Du bist so nah. Das Problem ist, dass Sie die Option: source missbrauchen. : source sollte auf die polymorphe Zugehörigkeit zu Beziehung verweisen. Dann müssen Sie nur noch angeben: source_type für die Beziehung, die Sie definieren möchten.

Mit diesem Fix für das Widget-Modell sollten Sie genau das tun, wonach Sie suchen.

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

Oh mein Gott, das ist so schmerzlich offensichtlich, dass ich nicht glauben kann, dass ich direkt darüber glasiert bin. Danke EmFi!
Cory

Kein Problem, ich glaube, ich habe mich ungefähr einen Tag lang darüber gequält, wie ich das machen soll, als ich das erste Mal darauf gestoßen bin. Es hat nicht geholfen, dass es eines der ersten Dinge war, die ich in Rails versuchte, ohne einem Tutorial / Buch zu folgen.
EmFi

1
Wie scotkf hervorhebt, gibt es in ActiveRecord 3.1.1 eine Regression, die dieses Verhalten blockiert. Durch ein Upgrade auf 3.1.2 funktioniert diese Lösung.
EmFi

6
Das Gleiche wie das, was @Shtirlic erwähnt hat. Gibt es eine Möglichkeit, source_type nicht anzugeben, sodass Sie eine gemischte Ergebnismenge haben? Wenn jemand dies gelöst hat, würde gerne wissen, wie.
Damon Aw

3
Funktioniert immer noch ab Rails 4.2.0. Gibt es heutzutage jedoch eine Möglichkeit, dies ohne source_type und zwei separate Assoziationen zu erreichen?
Emeka

3

Wie oben erwähnt, funktioniert dies mit Rails 3.1.1 aufgrund eines Fehlers in: source nicht, ist jedoch in Rails 3.1.2 behoben


-4

hat viele: durch und polymorph arbeiten nicht zusammen. Wenn Sie versuchen, direkt auf sie zuzugreifen, sollte ein Fehler ausgegeben werden. Wenn ich mich nicht irre, müssen Sie widget.people und die Push-Routine von Hand schreiben.

Ich denke nicht, dass es ein Fehler ist, es ist nur etwas, das noch nicht implementiert wurde. Ich würde mir vorstellen, dass wir es in der Funktion sehen, weil jeder einen Fall hat, in dem er es verwenden könnte.


6
Sie arbeiten zusammen. Zum Beispiel: has_many: Abonnements ,: as =>: abonnierbar has_many: Abonnenten ,: bis =>: Abonnements ,: source =>: user
ScottJ

Ich werde in naher Zukunft ein Beispiel für meinen fehlerhaften Code als separaten Beitrag veröffentlichen :) Es würde mir viel Kopfzerbrechen ersparen, herauszufinden, wie ich diesen Fehler umgehen kann.
cgr
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.