2011-04-03 32 views
3

我在一個我正在開發的rails應用程序中遇到過這種相當奇怪的行爲。當它的超類是抽象的時,爲什麼rails不尊重STI的belongs_to關聯對象的類型?

我有多種類型的崗位在繼承層級結構中,一個帖子的has_many FeedEntries。

class Post < ActiveRecord::Base 
    has_many :feed_entries 
end 

class Post::BlogPost < Post; end 
class Post::Discussion < Post; end 
class Post::Article < Post; end 

class FeedEntry < ActiveRecord::Base 
    belongs_to :post 
end 

現在,當我把一切都設置爲之前,調用已保存的對象上FeedEntry#後總是返回正確的(子)類型的對象,正如我所期望的。但是,如果我讓郵政抽象(它確實應該是 - 超不應該在這個模型實例化):

class Post < ActiveRecord::Base 
    has_many :feed_entries 
    self.abstract_class = true 
end 

_(注:我編輯此代碼段考慮到tomafro的建議之下,如設置self.abstract_class似乎比覆蓋self.abstract_class更加習慣用法。但是,相同的行爲仍然存在。)

...然後在先前保存的對象上調用FeedEntry#post關聯返回Post類型的對象。這似乎是相反的(鑑於抽象類聲明明確指出該類不應該被實例化),並且我不能想到這種行爲的原因。

所以,是有一些原因我沒有變,或者是一個錯誤,或者其他什麼東西?

回答

5

通過基礎對象指定self.abstract_class = true,你基本上是禁用STI。設置self.abstract_class = true實際上告訴ActiveRecord有不是與該類關聯的數據庫表,因此您的繼承類將擁有自己的數據庫表。

這聽起來像你想要做的是使用初始化方法只允許實例刪除self.abstract_class = true和模擬一個抽象類,如果類是Post類型的

例如:

class Post < ActiveRecord::Base  
    def initialize 
    raise "Post cannot be instantiated directly" if self.class == Post 
    end 
end 

這樣一來,您維護您的STI模型,也有僞抽象基類。希望這可以幫助!

+0

啊哈!那就是 - 我認爲activerecord的「抽象類」屬性大致相當於它的java-ish定義(即 - 一個不能直接實例化的類),實際上它明顯意味着不同的東西。非常感謝,這很好地解決了它! – mistertim 2011-04-05 10:41:29

+0

如果你覺得這有幫助,你會介意接受答案嗎?謝謝!! – MikeH 2011-04-08 15:50:39

+0

啊,當然!抱歉耽擱了。謝謝! – mistertim 2011-04-11 11:43:17

0

通過覆蓋超類中的abstract_class?方法,abstract_class?將對所有子類(而不僅僅是超類)返回true。

相反,我認爲你應該使用:

class Post < ActiveRecord::Base 
    self.abstract_class = true 
end 

我還沒有嘗試過,但我相信,這將解決您的問題。

+0

啊!非常好的一點。我現在就試試。謝謝湯姆! – mistertim 2011-04-03 13:52:51

+0

啊 - 可悲的不是。行爲與self.abstract_class = true相同。我認爲這更具慣用性,所以我會更新我的問題中的代碼以反映它。 – mistertim 2011-04-03 13:55:58