2012-02-20 15 views
19

mam mapowanie 2 modele:Szyny model, który posiada zarówno 'has_one' i 'has_many', ale z pewnymi contraints

User 
Account 

class Account 
    has_many :users 


class User 
    has_one :account 

tabeli użytkownika jako account_id w nim.

Teraz na modelu konta chcę utworzyć "głównego użytkownika", którego konto ma tylko 1. Tabela użytkownika ma flagę typu boolean: is_primary, jak utworzyć has_one po stronie konta dla użytkownika, który ma odwzorowany atrybut is_primary i account_id.

Więc SQL wyglądałby następująco:

SELECT * FROM users where account_id=123 and is_primary = 1 

Więc chcę:

Użytkownik ma konto. Konto ma wielu użytkowników i ma również jednego głównego użytkownika.

Odpowiedz

41

Approach 1 - Dodaj nowe stowarzyszenie

Dodaj stowarzyszenie has_one z where lambda. Pozwala to na pracę w ramach obecnego schematu.

class Account 
    has_many :users 
    has_one :primary_user, -> { where(is_primary: true) }, :class_name=> "User" 
end 

Teraz:

account.users #returns all users associated with the account 
account.primary_user #returns the primary user associated with the account 
# creates a user with is_primary set to true 
account.build_primary_user(name: 'foo bar', email: '[email protected]') 

Podejście 2 - dodaj metodę Stowarzyszenie

class Account 
    has_many :users do 
    def primary 
     where(:is_primary => true).first 
    end 
    end 
end 

Teraz:

account.users.primary # returns the primary account 
+0

dzięki za zapewnienie opcji! – Blankman

+0

doceniłby twoje komentarze na ten temat, ponieważ jest to powiązane: http://stackoverflow.com/questions/9365068/rails-model-that-has-both-has-one-and-has-many-but-with-some -ograniczenia – Blankman

+0

Ładne i czyste podejście. Czy mógłbyś wyjaśnić, jak zaktualizować primary_user w formularzu aktualizacji # konta za pomocą (collection_) wyboru wszystkich użytkowników, używając podejścia 1? Dziękujemy – Patient55

6

Prawdopodobnie byłoby prostsze dodać primary_user_id pole na konto i dodać 'has_one Stowarzyszenie dla primary_user:

class Account 
    has_many :users 
    has_one :primary_user, :class_name => "User" 
end 

class User 
    has_one :account 
end 

Jeśli musisz użyć istniejącego schematu (z: is_primary flagi wartości logicznej) można dodać zakresu tak:

class User 
    has_one :account 
    scope :primary, where(:is_primary => true) 
end 

a następnie łańcucha zakres do odnośnika użytkowników:

account = Account.find(1) 
primary_user = account.users.primary.first 
+0

+1 za pierwszym podejściem. Chociaż 'account.users.primary' jest bardziej wyraziste niż' account.users.primary.first' –

+1

Bardzo prawdziwe, ponieważ konwencja nazewnictwa nie działa dobrze. Ale można to łatwo naprawić, nazywając zakres "prawyborami" i określając metodę klasy jako "def selftrrimary; primaries.first; koniec'. Teraz możesz użyć ogólnego zakresu 'primaries' lub metody' primary' w odniesieniu do pojedynczego rekordu (gdzie oczekuje się tylko 1) – PinnyM

Powiązane problemy