2010-01-24 9 views
7

Mam model, Couple, który ma dwie kolumny, first_person_id i second_person_id i inny model Person, których podstawowym kluczem jest person_id i ma kolumnę nameActiveRecord has_many gdzie dwie kolumny w tabeli A są klucze podstawowego w tabeli B

oto wykorzystanie chcę:

#including 'Person' model for eager loading, this is crucial for me 
c = Couple.find(:all, :include => :persons)[0] 
puts "#{c.first_person.name} and #{c.second_person.name}" 

Więc jak mogę to zrobić?

+0

Jeśli używasz szyny, dlaczego kluczem podstawowym modelu Person być „person_id "a nie tylko" id "? – tfwright

+0

Zmieniłem nazwy moich modeli dla tego posta, ponieważ chciałbym, aby ich nazwy nie były dostępne w Internecie. Powinien to być "id", ale nie jest to trudna naprawa. Po prostu użyj 'set_primary_key'. – user94154

Odpowiedz

13

relacji zgłoszone Couple powinna wyglądać następująco:

class Couple 
    named_scope :with_people, { :include => [:first_person, :second_person] } 
    belongs_to :first_person, :class_name => 'Person' 
    belongs_to :second_person, :class_name => 'Person' 
end 

#usage: 
Couple.with_people.first 
# => <Couple ... @first_person: <Person ...>, @second_person: <Person ...>> 

Ci w Person zależeć od tego, czy Person może być częścią więcej niż jednego Couple. Jeśli Person może należeć tylko do jednej Couple i nie może być „pierwszym” Person na jednym i tym Second na innym, może chcesz:

class Person 
    has_one :couple_as_first_person, :foreign_key => 'first_person_id', :class_name => 'Couple' 
    has_one :couple_as_second_person, :foreign_key => 'second_person_id', :class_name => 'Couple' 

    def couple 
    couple_as_first_person || couple_as_second_person 
    end 
end 

Jeśli Person może należeć do kilku Couple s, a tam nie sposób stwierdzić, czy są one „pierwszy” i „drugi” w danym Couple, możesz:

class Person 
    has_many :couples_as_first_person, :foreign_key => 'first_person_id', :class_name => 'Couple' 
    has_many :couples_as_second_person, :foreign_key => 'second_person_id', :class_name => 'Couple' 

    def couples 
    couples_as_first_person + couples_as_second_person 
    end 
end 
+0

To dobrze napisana, dobrze przemyślana odpowiedź. Dzięki wielkie. Niedługo to sprawdzę i dam ci znać. – user94154

+0

jeszcze tego nie testowałem, ale WYGRAJ :) – user94154

+0

Po prostu zrobiłem coś takiego używając AREL: 'def widgets; Widget.where ( Wiget.arel_table [: asset1_id] .eq (id) lub ( Widget.arel_table [: asset2_id] .eq (id) ) ); koniec' – thekingoftruth

0

Nietestowane, ale według Rails API documentation, może coś takiego:

class Couple < ActiveRecord::Base 
    has_one :person, :foreign_key => :first_person_id 
    has_one :person, :foreign_key => :second_person_id 
end 
+0

Powinny one należeć do belongs_to, a nie has_one, ponieważ klucze obce są w tym modelu. – tfwright

0

teorii tylko, niesprawdzone:

Utwórz dwie podklasy osobę:

class FirstPerson < Person 
    belongs_to :couple 

class SecondPerson < Person 
    belongs_to :couple 

para klasy has_many każdego :

class Couple 
    has_many :first_persons, :foreign_key => :first_person_id 
    has_many :second_persons, :foreign_key => :second_person_id 

Następnie znajdź:

Couple.all(:include => [:first_persons, :second_persons]) 
+0

nie powinien mieć pary 'has_one: first_person' i': second_person'? – user94154