Meine Tabellen sind so eingerichtet, dass Child
eine 1:1
Beziehung mit Parent
hat.Erweitern einer ActiveRecord Polymorphic Association mit JOIN-Anweisungen?
teilen Sie einen Primärschlüssel (id
):
Parent
hatid
undtype
undname
Child
hatid
undhealth
Die Child
ist ein polymorpher Erbe des Parent
. Mein Ziel ist, dass Child.find(1)
ein Objekt Child
zurückgeben sollte, das sowohl auf name
als auch auf health
reagiert. Die SQL-Anweisung würde hypothetisch wie folgt aussehen:
SELECT parents.id, parents.name, childs.health FROM parents LEFT JOIN childs ON childs.id = Parents.id WHERE parents.id = 1 AND parents.type = 'Child' LIMIT 1
So habe ich versucht Polymorphe Vererbung in Activerecord zu verwenden:
class Parent < ApplicationRecord
class Child < Parent
Wenn ich versuche, Child.find(1)
auszuführen, ich sehe:
SELECT `parents`.* FROM `parents` WHERE `parents`.`type` IN ('Child') AND `parents`.`ID` = 1 LIMIT 1 => #<Child id: 1, type: "Child", name: "Hello">
Bemerkenswerterweise gibt es keine JOIN
auf der child
Tabelle, aber ich erhalte ein Child
Objekt zurück. Dies führt zu dem unerwarteten Verhalten, dass das Objekt Child
nicht auf health
reagiert. Seltsamerweise, wenn ich eine explizite Tabelle Assoziation zum Child
Klasse (self.table_name = "childs"
) hinzufügen, dann ändert sich die Abfragemuster:
> c = Child.find(1) Obtainable Load (0.3ms) SELECT `childs`.* FROM `childs` WHERE `childs`.`ID` = 2 LIMIT 1
Jetzt kann ich die health
zugreifen, aber nicht die type
oder name
.
Wie kann ich diese JOIN-Verknüpfung korrekt erstellen, sodass ein Versuch, ein Child
-Objekt erfolgreich zu laden, die Daten aus dem übergeordneten verknüpft?
Edit: diese Tabellen außerhalb eines Active Migration erstellt wurden (sie werden auch von anderen, bereits bestehenden, nicht-Ruby-Anwendungen zugegriffen wird), so habe ich keine Möglichkeit, ihr Schema zu ändern. Ich kann mir einige ausgefallene Metaprogrammierungsansätze vorstellen, wie zum Beispiel die Antwort auf method_missing
, die mir vielleicht die fehlenden Attribute durch einen Join laden lassen würden ... aber ich fürchte, dass ich am Ende ein paar ActiveRecord neu implementieren muss, wie delete
, create
usw. (was zu Fehlern führen wird). Also suche ich nach einem nativen/sauberen (ish) Weg, dies zu erreichen.
Excellent! Große Lösung für ein nicht standardmäßiges Problem. Schnelles Follow-up aber: 'Child.new.save' erzeugt derzeit kein' Parent'-Objekt, und ebenfalls 'delete' wird die verbundenen Tabellen nicht bereinigen. Ich beabsichtige, 'before_ *' Filter zu verwenden, um die Buchhaltung selbst zu implementieren, aber ich bin neugierig, wenn Sie eine bessere Idee haben. –
Ich habe 'Child'-Klasse bearbeitet, so dass automatisch Eltern-Datensatz erstellt und gelöscht wird. 'c = Child.new' und dann' c.name = "Foo" '' c.save' und 'c.destroy' löschen –
Hinweis: Dies ist definitiv kein typischer" Rails-Weg ", aber es könnte funktionieren dieses Nicht-Standard-Problem. –