2010-01-12 16 views
9

Ich frage mich, in welchem ​​Ausmaß ich Verbände in Rails verwenden kann. Berücksichtigen Sie die folgenden:rails has_many: durch has_many: durch

class User < ActiveRecord::Base 
    has_one :provider 
    has_many :businesses, :through => :provider 
end 

class Provider < ActiveRecord::Base 
    has_many :businesses 
    has_many :bids, :through => :businesses 
    belongs_to :user 
end 

class Business < ActiveRecord::Base 
    has_many :bids 
    belongs_to :provider 
end 

class Bid < ActiveRecord::Base 
    belongs_to :business 
end 

Ich bin in der Lage, diese raffinierte Abkürzungen wie User.businesses einzurichten und Provider.bids aber was ist so etwas wie User.bids tun? Ist es möglich, sozusagen eine Assoziation zu assoziieren?

Antwort

5

Dies ist durchaus möglich, erfordert aber ein wenig mehr Arbeit. Die folgenden Modell verwendeten Definitionen in Verbindung mit dem nested_has_many plugin können Sie alle Gebote holen mit nur @user.bids

class User < ActiveRecord::Base 
    has_one :provider 
    has_many :businesses, :through => :provider 
    has_many :bids, :through => :businesses 
end 

class Provider < ActiveRecord::Base 
    has_many :businesses 
    has_many :bids, :through => :businesses 
    belongs_to :user 
end 

class Business < ActiveRecord::Base 
    has_many :bids 
    belongs_to :provider 
end 

class Bid < ActiveRecord::Base 
    belongs_to :business 
end 

jedoch immer ein Benutzer von einem Angebot zu einem Benutzer gehören, wird eine weitere Arbeit.

+2

Es ist möglich, aber müssen Sie vorsichtig sein, wie tief Sie verschachteln, weil Sie Ihre Datenbank und Rails App bahnen können. Davon abgesehen habe ich einen Blogpost verfasst, der detailliert beschreibt, wie man nested_has_many_through dazu benutzt: http://kconrails.com/2010/01/28/nestinghas_many-through-relationships-in-ruby-on-rails/ –

2

Obwohl es eine sehr nützliche Sache zu haben ist, kann man nicht has_many: durch eine has_many: through-Beziehung. Dies ist eine Einschränkung der Join-Engine.

Die Alternativen bestehen entweder darin, eine clevere Unterauswahl oder in diesem Fall eine Sub-Sub-Auswahl zu verwenden oder die Tabellen absichtlich zu denormalisieren, um die Join-Tiefe zu reduzieren.

Da beispielsweise ein Geschäft im Kontext eines Anbieters definiert wird, liegt es nahe, dass alle Bietelemente indirekt auch einem Anbieter zugewiesen werden. Wenn Sie eine direkte Verknüpfung zwischen Gebot und Anbieter erstellen, können Gebote direkt abgefragt werden.

0

Es gibt nichts hindert Sie so etwas wie dieses afaik tun:

class User < ActiveRecord::Base 
    has_one :provider 
    has_many :businesses, :through => :provider 

    def bids 
     user_bids = [] 
     businesses.each |business| do 
      user_bids += business.bids 
     end 
     user_bids 
    end 
end 

class Provider < ActiveRecord::Base 
    has_many :businesses 
    has_many :bids, :through => :businesses 
    belongs_to :user 
end 

class Business < ActiveRecord::Base 
    has_many :bids 
    belongs_to :provider 
end 

class Bid < ActiveRecord::Base 
    belongs_to :business 
end 

Dann ruft @ user.bids sollte das gewünschte Ergebnis, können Sie auch die Gebote zwischenzuspeichern und tun andere fancy stuff, wenn Sie wollen.

+0

Wie werden Gebote zwischengespeichert, da es sich um nicht statische Daten handelt? Wie können wir den Cache aktualisieren? –

4

Wenn Sie nur die Datensätze abrufen möchten, warum nicht verwenden Sie #delegate? Es funktioniert gut, zumindest in dem Szenario, das Sie beschrieben haben.

class User < ActiveRecord::Base 
    has_one :provider 
    delegates :bids, :to => :provider 
end 

class Provider < ActiveRecord::Base 
    has_many :businesses 
    has_many :bids, :through => :businesses 
    belongs_to :user 
end 

class Business < ActiveRecord::Base 
    has_many :bids 
    belongs_to :provider 
end 

class Bid < ActiveRecord::Base 
    belongs_to :business 
end 

Obwohl in meiner nicht so bescheiden-Meinung nach sollte man die Kette nur die Methoden, weil es einfacher ist, und du bist nicht mehr die Leistungssteigerung zu erzielen, wenn Sie mit einiger verrückten benutzerdefinierten SQL gehen, wie Tadman sagt.