2010-01-12 22 views
9

Mi chiedo fino a che punto posso utilizzare le associazioni in Rails. Prendere in considerazione quanto segue:rails has_many: through has_many: through

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 

Sono in grado di impostare queste scorciatoie nifty come User.businesses e Provider.bids ma per quanto riguarda fare qualcosa di simile User.bids? È possibile associare un'associazione, per così dire?

risposta

5

Questo è interamente possibile, ma richiede un piccolo lavoro in più. Le seguenti definizioni del modello utilizzato in combinazione con il nested_has_many plugin è possibile recuperare tutte le offerte che appartengono a un utente con solo @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 

Tuttavia ottenere un utente da un offerta avrà un più lavoro.

+2

È possibile, ma è necessario fare attenzione a quanto profondamente si nidifica, perché è possibile impantanarsi l'app del database e delle guide. Detto questo, ho scritto un post sul blog che spiega come usare nested_has_many_through per fare questo: http://kconrails.com/2010/01/28/nesting-has_many-through-relationships-in-ruby-on-rails/ –

2

Sebbene sia una cosa molto utile da avere, non è possibile has_many: attraverso has_many: attraverso la relazione. Questa è una limitazione del motore di join.

Le alternative sono o per utilizzare una sottoselezione intelligente, o in questo caso una selezione sub-sub, o per denormalizzare deliberatamente le tabelle in modo da ridurre la profondità del join.

Ad esempio, poiché un Business è definito nel contesto di un Provider, è ovvio che qualsiasi elemento Bid viene assegnato anche, indirettamente, a un Provider. La creazione di un'associazione diretta tra offerta e provider renderebbe le richieste di query direttamente facili.

0

Non c'è nulla che possa impedire che si fare qualcosa di simile per quanto ne so:

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 

quindi chiamando @ user.bids dovrebbe produrre il risultato desiderato, è anche possibile memorizzare nella cache le offerte e fare altre cose di fantasia se si vuole.

+0

Come verranno memorizzate le "offerte" in quanto sono dati non statici? Come sappiamo di aggiornare la cache? –

4

Se si desidera solo recuperare i record, perché non utilizzare l'uso #delegate? Funziona bene, almeno nello scenario che hai descritto.

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 

Anche se nel mio non-così-umile parere si deve solo concatenare i metodi perché è più semplice, e non sei più raggiungere l'incremento delle prestazioni a meno che non si va con un po 'di SQL personalizzata folle come Tadman dice.

Problemi correlati