2012-07-26 5 views
25

On Rails vererben 3.2.6, ich habe eine Klasse, die von Active erbt :: Base:Prevent STI, wenn sie von einem Active Modell

class Section < ActiveRecord::Base 
    ... 
end 

Als ich von dieser Klasse erben, Rails gehe ich davon aus STI wollen:

class AnotherSection < Section 
    ..Rails assumes I have a type field, etc... 
end 

ich möchte in der Lage sein, von der Section Klasse zu erben und die Unterklasse als normale Ruby-Unterklasse verwenden, ohne die Rails STI Magie.

Gibt es eine Möglichkeit, STI zu verhindern, wenn von einem ActiveRecord::Base Modell abgeleitet wird?

+2

Wenn Sie nicht eine 'type'-Spalte haben, die Sie nicht stören sollte ... wenn Sie einen' type' haben, dann können Sie es deaktivieren, indem Sie tun, was @Veraticus sagte .. – shuriu

+0

In der Tat Sie immer noch haben STI: Instanzen von beiden Klassen werden in der gleichen Tabelle gespeichert, was ist die Definition von STI (Single Table Inheritance). Sie wollen einfach keine Diskriminatorspalte (den "Typ") haben. Wie werden Sie jedoch wissen, ob jeder Datensatz aus Abschnitten ein einfacher Abschnitt oder ein anderer Abschnitt ist? – atorres

Antwort

28

Sie können dies erreichen, indem die inheritance_column für das Modell zu deaktivieren, etwa so:

class AnotherSection < Section 
    # disable STI 
    self.inheritance_column = :_type_disabled 

end 
+7

Das oder eine nicht vorhandene Spalte reicht aus. – shuriu

+3

self.inheritance_column = nil hat für mich funktioniert (aber ich habe es schon lange ausprobiert und es war rails 3.2) – Alexis

+0

das disabled discriminator column. Aber beide Klassen sind in der gleichen Tabelle gespeichert, was die Definition von STI (Single Table Inheritance) ist. Sie haben gerade die Diskriminatorspalte entfernt, und Ruby kann nicht entscheiden, was der Typ jedes gespeicherten Datensatzes ist (Sie müssen beim Laden entscheiden) – atorres

11

Die akzeptierte Antwort wird auf jeden Fall arbeiten, aber die empfohlene (ich wage zu sagen „richtige“ :) Weg ist abstract_class einstellen :

class Section < ActiveRecord::Base 
    self.abstract_class = true 
end 
+3

Dies ist der richtige Ansatz, und es gibt seit Rails 1.1. –

+0

Das funktioniert nicht für mich. Ich kann kein Objekt dieser Modellklasse instantiieren ... ('NotImplementedError: MyModel ist eine abstrakte Klasse und kann nicht instanziiert werden.'). Also bitte überarbeiten Sie Ihre Antwort @smathy – deepflame

+0

@deeflame Sie können keine abstrakte Klasse instantiieren, es ist abstrakt. – smathy

1

Die einzige vollständig unterstützte Strategie zum Speichern der Vererbung auf ActiveRecord ist STI. Sie können jedoch eine konkrete Vererbung der Klassen-Tabelle auf eigenes Risiko simulieren. Die konkrete Klassen-Tabellen-Vererbung mit abstrakter Oberklasse funktioniert gut, wie Smathy zeigt.

ABER ... Wenn Sie möchten, ist AnotherSection nur eine gewöhnliche Klasse (die nicht in der Datenbank beibehalten wird), können Sie die Diskriminator-Spalte deaktivieren (wie von Veraticus vorgeschlagen). Wenn Sie jedoch die AnotherSection speichern, wird es in der gleichen Tabelle wie Abschnitt gespeichert, und Sie können sie nicht voneinander unterscheiden. Auch, wenn Sie verwenden AnotherSection zu finden, ein Abschnitt, wird es geben eine AnotherSection, brechen die ursprüngliche Instanziierung:

#create a Section and saves it 
    sect = Section.create() 
    sect.save() 
    #retrieve the Section as a AnotherSection, breaking polymorphism... 
    sect = AnotherSection.find(sect.id) 
    # another section is more than a section, it is inconsistent. 

Wenn AnotherSection ist nicht beibehalten werden soll, den sichersten Weg es die Persistenz Operationen, wie save() und finden() außer Kraft zu setzen:

class AnotherSection < Section 
     # disable STI, as pointed by Veraticus 
     self.inheritance_column = :_type_disabled 
     # disable save and finding 
     def save(*args) 
     #exception? do nothing? 
     end 
     def find(*args) 
     #exception? do nothing? 
     end 
     def find_by(*args) 
     #exception? do nothing? 
     end 
     # this does not stops here! there is first, last, and even a forty_two finder method! not to mention associations... 
    end 

auf den Punkt gebracht, können Sie dies tun, aber Hier darf man sich. Das Risiko ist hoch. Sie sollten eine andere Option in Erwägung ziehen, z. B. die Verwendung von MIXIN anstelle von Vererbung.