2016-03-23 10 views
1

Eine Frage zu Rails association, wo eine has_one Zuordnung zu einem von zwei möglichen Modellen ist. Wie eine polymorphe Assoziation, aber andersherum.Schienen - hat eine Verbindung zu einem von zwei möglichen Modellen

Ich habe zwei verschiedene Arten von Bankkonten So gehört sowohl UserConfig zu:

class SwedishBankAccount 
    belongs_to :user_config 
end 

class ForeignBankAccount 
    belongs_to :user_config 
end 

Die Frage ist, wie dies in meinem UserConfig zu verwalten. Es sollte eine has_one Zuordnung zu entweder SwedishBankAccount ODER ForeignBankAccount, aber nicht zu beiden haben.

+0

Warum haben Sie nicht "polymorphe" Assoziation hier verwendet? –

+0

Würde es Ihnen etwas ausmachen, ein Beispiel zu geben, wie ich das machen könnte? Vielleicht bin ich nur blind, aber ich sehe nicht wie :) – ehannes

+0

in Antwort geschrieben. –

Antwort

2

Sie können eine ploymorphe Beziehung verwenden. In target_id und target_type Spalt in UserConfig Modell

class UserConfig < ActiveRecord::Base 
    belongs_to :target, :polymorphic => true 
end 

Dann verwenden Sie nur für das Modell SwedishBankAccount Wie

class SwedishBankAccount < ActiveRecord::Base 
    has_one :user_config, :as => :target 
end 

Und in Modell ForeignBankAccount Als

class ForeignBankAccount < ActiveRecord::Base 
    has_one :user_config, :as => :target 
end 
+0

Es fühlt sich komisch an, dass die 'UserConfig'' '' '' 'auf das Bankkonto gehört, aber wenn ich Recht habe, entscheidet das nur, wo der' fremde_Schlüssel' liegt. – ehannes

+0

Tatsächlich ist Ihr Fremdschlüssel des Accounts in 'UserConfig' Modell mit 'type' gespeichert –

+0

Ich dachte über die Assoziationsnamen mehr als die Platzierung des' foreign_key'. Eine 'UserConfig' kann ohne jede Art von Bankverbindung existieren, aber es sollte nicht möglich sein, dass ein 'SwedishBankAccount' ohne eine zugehörige' UserConfig' existiert. Die 'UserConfig' besitzt das Bankkonto und nicht umgekehrt. Ich denke, dass es etwas unklar wird, ob das 'has_one' stattdessen auf das Bankkonto verschoben wird. Aber das ist nur meine Meinung :) – ehannes

0

Sie können ein neues Modell namens account erstellen, wobei user_id ein Primärschlüssel "no duplicates" und eine account_id ist, die auf seinen Datensatz in ForeignBankAccount oder SweditshBankAccount verweist.

Auf diese Weise stellen Sie sicher, dass keine Benutzer mehr als 1 Konto gleichzeitig haben.

+0

Danke für Ihre Antwort. In meinem Fall hat ein 'Benutzer' eine' UserConfig' und ein 'Profil'. Die 'UserConfig' sollte dann eine Verbindung zum Bankkonto haben. Die Einführung einer neuen "Account" -Klasse ist nicht geeignet. – ehannes

1

können Sie abstrakte Klasse erstellen BankAccount für diese Modelle:

class BankAccount < ActiveRecord::Base 
    self.abstract_class = true 
    belongs_to :user_config 
end 

class SwedishBankAccount < BankAccount 
end 

class ForeignBankAccount < BankAccount 
end 

class UserConfig < ActiveRecord::Base 
    has_one :bank_account 
end 

Hier wird für BankAccount keine Tabelle, aber Sie können gemeinsame Teile Ihrer Modelle setzen dort.

+0

Wusste nicht, dass Sie eine Assoziation zu einer abstrakten Klasse haben könnten. Ich werde es testen! :) – ehannes

+1

Ich bevorzuge diese Lösung. Es ist klar, dass die 'UserConfig' der Eigentümer des' BankAccounts' ist, und auch, wie Sie sagen, können allgemeine Teile in die abstrakte Klasse eingefügt werden. – ehannes

+0

Ich habe einige Probleme mit Ihrem Ansatz festgestellt. Wenn ich versuche, mit 'user_config.bank_account' auf das Benutzerkonto zuzugreifen, bekomme ich' ActiveRecord :: StatementInvalid: Tabelle nicht gefunden '' '. Der abstrakten Klasse fehlt offensichtlich ein Tabellenname. Irgendein Gedanke, wie ich das lösen kann? – ehannes

1

eine Assoziation zu einer abstrakten Klasse zu haben, wie zishe vorgeschlagen hat, war leider keine gute Idee (siehe Kommentare zu dieser Antwort). Vishal JAINs Antwort wird funktionieren, aber ich denke, dass es aufgrund des Eigentümerwechsels schwieriger wird, ein korrektes Bild der Architektur zu bekommen.

Ich endete mit Zuordnungen zu beiden Arten von Bankkonten. Eine hässliche Lösung, aber es war das Beste, was ich mir vorstellen konnte. Wenn jemand eine bessere Idee hat, bitte teilen Sie Ihre Gedanken! :)

class UserConfig < ActiveRecord::Base 
    has_one :swedish_bank_account 
    has_one :foreign_bank_account 

    enum bank_account_type [:swedish_bank_account, foreign_bank_account] 

    # Returns bank account of type determined by bank_account_type. 
    # Returns nil if no account is associated. 
    def bank_account 
    return swedish_bank_account if swedish_bank_account? 
    return foreign_bank_account if foreign_bank_account? 
    end 
end 
+0

Dieser Ansatz ist fehleranfällig. Eine 'UserConfig' kann tatsächlich zwei Bankkonten gleichzeitig haben. Wenn jemand direkt den 'swedish_bank_account' oder den 'foreign_bank_account' aufruft, ohne die' bank_account' Methode zu verwenden, besteht eine 50% ige Chance, dass das zurückgegebene Bankkonto gleich Null oder falsch ist. – ehannes

Verwandte Themen