2012-07-26 47 views
25

On Rails的3.2.6,我有一個從ActiveRecord的繼承的類:: Base的:防止STI

class Section < ActiveRecord::Base 
    ... 
end 

當我從該類繼承,Rails會以爲我想STI:

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

我希望能夠從Section類繼承並使用子類作爲一個正常的Ruby的子類,而Rails的STI魔力。

有沒有一種方法,以防止STI從ActiveRecord::Base模型繼承什麼時候?

+2

,如果你沒有一個'type'列,不應該打擾你......如果你有一個'type',那麼你可以做什麼@Veraticus表示禁用它.. – shuriu 2012-07-26 19:19:01

+0

其實你還是有STI:來自兩個類的實例將存儲在同一個表中,STI(Single Table Inheritance)的定義是什麼。你只是不想有鑑別器列(「類型」)。但是,如何知道段中的每條記錄是普通段還是AnotherSection? – atorres 2017-01-21 16:13:28

回答

28

您可以通過禁用inheritance_column爲模型實現這一點,就像這樣:

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

end 
+7

這個,或者任何不存在的列就足夠了。 – shuriu 2012-07-26 19:19:28

+3

self.inheritance_column =零工作對我來說(但我想它很久以前,它是軌道3.2) – Alexis 2014-12-26 11:03:28

+0

此禁用鑑別列。但是這兩個類都存儲在同一個表中,STI(Single Table Inheritance)的定義是什麼。你只是刪除了鑑別列,紅寶石將無法決定什麼是每個存儲記錄的(你需要決定什麼時候加載) – atorres 2017-01-21 16:43:19

11

接受的答案肯定會工作,但推薦的(我敢說「正確的」 :)方法是將abstract_class

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

這是正確的做法,它已經存在了,因爲Rails的1.1型。 – 2015-12-14 15:25:22

+0

這不適合我。我不能實例化這個模型類的任何對象......('NotImplementedError:MyModel是一個抽象類,不能實例化.')。所以請修改你的答案@smathy – deepflame 2016-08-04 19:55:15

+0

@deepflame你不能實例化一個抽象類,它是抽象的。 – smathy 2016-08-05 19:45:34

1

在ActiveRecord上存儲繼承的唯一完全支持策略是STI。但是,您可以自行承擔風險,模擬具體的類表繼承。正如smathy指出的那樣,具有抽象超類的具體類表繼承工作正常。

但是......如果你想要製作另一部分只是一個普通的類(它不會被持久化在數據庫中),你可以禁用鑑別器列(如Veraticus所建議的那樣)。但是,如果您保存AnotherSection將在同一個表的部分依然存在,你將不能夠告訴他們分開。另外,如果你使用AnotherSection找到,它會返回一個AnotherSection,打破了原有的實例:

#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. 

如果AnotherSection並不打算堅持着,最安全的路徑它覆蓋持久化操作,如保存()和find():

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 

概括地說,你可以這樣做,但你SHOULDN'T。風險很高。 你應該考慮其他選項,比如使用MIXIN,而不是繼承的。