2010-02-08 10 views
6

Ho due classi che vorrei precisare quanto segue:associazioni multiple per Same Modello

class Club < ActiveRecord::Base 
    belongs_to :president, :class_name => "Person", :foreign_key => "president_id" 
    belongs_to :vice_president, 
      :class_name => "Person", 
      :foreign_key => "vice_president_id" 
end 

class Person < ActiveRecord::Base 
    has_one :club, :conditions => 
    ['president_id = ? OR vice_president_id = ?', '#{self.id}', '#{self.id}'] 
end 

Questo non funziona e mi dà un errore quando si cerca di ottenere l'associazione Club dall'oggetto persona. L'errore è perché sto cercando person_id nella tabella del club quando ho guardato l'SQL. Posso aggirarlo dichiarando più has_one associazioni, ma sento che questo è il modo sbagliato di farlo.

Una persona può essere solo il presidente o il vicepresidente di un club.

Chiunque sia in grado di offrire un po 'di consigli su questo argomento, sarei molto riconoscente.

risposta

8

tua condizione has_one non funzionerà mai in Rails, per quanto ne so.

È necessario un esplicito has_one o belongs_to o has_many per "collegamento", su entrambe le tabelle. Quindi, se hai due "link", hai bisogno di due has_one e due belongs_to. Ecco come funziona.

In secondo luogo, penso che dovresti riconsiderare i tuoi modelli. Il modo in cui lo fai, una persona non può essere il presidente di un club e un dipendente, allo stesso tempo. O essere il presidente di due club. Anche se non li hai adesso, possono venire in futuro - è più facile rimanere flessibili in questo momento.

Un modo flessibile per fare ciò è utilizzare un has_many :through con una tabella intermedia che specifica il ruolo. In altre parole:

# The memberships table has a person_id, club_id and role_id, all integers 

class Membership < ActiveRecord::Base 
    belongs_to :club 
    belongs_to :person 
    validates_presence_of :role_id 
    validates_numericality_of :role_id 
end 

class Club < ActiveRecord::Base 
    has_many :memberships, :dependent => :delete_all 
    has_many :people, :through => :memberships 
end 

class Person < ActiveRecord::Base 
    has_many :memberships, :dependent => :delete_all 
    has_many :clubs, :through => :memberships 
end 

Ora, partendo dal presupposto che ROLE_ID = 0 significa dipendente, ROLE_ID = 1 significa presidente, e ROLE_ID = 2 significa vice_president, è possibile utilizzarlo in questo modo:

tyler = Person.find(1) # person_id is 1 
other = Person.find(2) # person_id is 2 
c = Club.find(1) # club_id is 1 

tyler.clubs # returns all the clubs this person is "member" of 
c.people # returns all the "members" of this club, no matter their role 

#make tyler the president of c 
tyler.memberships.create(:club_id => 1, :role_id => 1) 

#make other the vicepresident of c 
#but using c.memberships instead of other.memberships (works both ways) 
c.memberships.create(:person_id => 2, :role_id => 1) 

#find the (first) president of c 
c.memberships.find_by_role_id(1).person 

#find the (first) vicepresident of c 
c.memberships.find_by_role_id(2).person 

#find all the employees of c 
c.memberships.find_all_by_role_id(0).collect { |m| m.person } 

#find all the clubs of which tyler is president 
tyler.memberships.find_all_by_role_id(1).collect { |m| m.club } 

Note aggiuntive :

  • Si potrebbe completare questo con un tavolo ruoli e modello. I ruoli avrebbero solo un nome, i ruoli corrisponderebbero alle relazioni have_many e al ruolo belong_to.In alternativa, è possibile definire i metodi nelle appartenenze per ottenere il nome del ruolo (se 0, restituisce "impiegato", se 1, "presidente", ecc.
  • È possibile aggiungere convalide su membri, quindi non più di una persona può essere nominata presidente di un determinato club, o dello stesso dipendente nello stesso club due volte Più tardi, se inizi a ricevere "casi eccezionali" in cui una persona deve trovarsi in due punti, dovrai solo adattare le convalide
+0

Ok, questo sembra decisamente una struttura migliore. Tuttavia non sono sicuro di come la cosa dipendente funzioni in questo. La designazione del dipendente è davvero indipendente se fa parte di un club o no, quindi non penso che dovrebbe far parte del tavolo dei soci. Per inciso, utilizzo già un modello di ruoli per i diversi ruoli dei dipendenti che abbiamo. Quindi forse sul modello Persona ci dovrebbe essere un'associazione con un has_one EmployeeRole e che fornisce il tipo di dipendente? – adimitri

+0

Ciao! Non sono sicuro di capire cosa intendi per 'davvero indipendente se fanno parte di un club o no'. Se si dispone di una tabella ruoli con ruoli dipendenti, è possibile aggiungere altri 2 ("presidente" e "vicepresidente") e utilizzare solo una cosa. Perché vuoi che siano separati? – kikito

+0

Questa applicazione è per un'organizzazione governativa studentesca in un campus universitario. Finanziano molti club gestiti da studenti e con 4 posizioni di e-board (Presidente, VP, Segretario Tesoriere). I dipendenti sono del governo studentesco e anche studenti, ma non ha nulla a che fare con il club. Quindi possono far parte di un club e-board e un dipendente. – adimitri

0

Penso che le vostre associazioni siano nel modo sbagliato. A tuo modo è difficile assegnare un presidente o un vicepresidente.

lo farei in questo modo:

class Club < ActiveRecord::Base 
    has_one :president, 
      :class_name => "Person", 
      :foreign_key => 'president_club_id' 
    has_one :vice_president, 
      :class_name => "Person", 
      :foreign_key => 'vice_president_club_id' 
end 

class Person < ActiveRecord::Base 
    belongs_to :club 
end 

Ora è possibile assegnare i ruoli come questo:

club.president = Person.create(:name => 'Tom') 
club.vice_president = Person.create(:name => 'Andrew') 
+0

Questo non funzionerebbe però perché allora avrei bisogno di un presidente_club_id e vice_president_club_id nella tabella Persone (e nella mia attuale applicazione hanno anche altre due posizioni). Inoltre dovrei avere più appartiene alla classe Person per quello Inoltre qualche peop Le potrebbe non essere responsabile dei club e piuttosto dei "dipendenti", quindi vorrei tenere la foreign_key fuori dal loro modello. – adimitri

0

ti suggerisco di introdurre un nuovo modello chiamato ruolo. Poi hanno il seguente:

class Club 
    has_many :roles 

    def president 
    end 

    def vice_president 
    end 

end 

class Person 
    belongs_to :role 
end 

class Role 
    has_one :person 
    belongs_to :club 
end 
0

Questo è il caso classico per le associazioni polimorfiche. ecco il link: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

Qualcosa di simile ..

class Club < ActiveRecord::Base 
    belongs_to :person, :polymorphic => true 

class Person < ActiveRecord::Base 
    has_one :club, :as => :position 
+0

Le associazioni polimorfiche non aiuterebbero a risolvere il problema qui perché le sue molteplici persone sono accessibili dallo stesso modello. Le associazioni polimorfiche sono per quando il tuo foreign_key può essere modelli diversi. – adimitri

Problemi correlati