2

我正在設計一個族譜導軌應用程序,並且在決定如何設計我的模型時遇到了一些麻煩。具體來說,我正在研究將在時間表中顯示的內容。時間軸上會出現許多「事物」。我已經決定我有兩種類型的「東西」:Event - 單一日期和Period - 開始和結束日期。這裏有 「東西」 的幾個例子,並在其中鍵入掉落:導軌模型的繼承

  • 誕生[Event]
  • 死亡[Event]
  • 婚姻[Event]
  • 公寓[Period]
  • 火化[Event]職業[Period]
  • 畢業[Event]
  • 家庭團聚[Event]
  • 離婚[Event]
  • 收養[Event]

本來,我打算在具有EventPeriod除了TimelineObject模型之外,還可以是模型,然後將上面列表中的每一項都作爲自己的模型。

因此,繼承是TimelineObject < ActiveRecord::BaseEvent < TimelineObjectPeriod < TimelineObject和(EG)Birth < Event和(EG)Residence < Period

在軌這樣,我可以做TimelineObject.all(或一些過濾器的個人),並得到所有時間軸上的對象。

但是,我遇到了如何在rails中實現這個問題。我研究了單表繼承(STI),但這似乎不太合適。這些東西會共享一些屬性,但它們不會共享更多的屬性,這樣會在數據庫中產生很多空值。我也想過爲此使用模塊,但不知道如何。

你會如何建議實施這些「事情」。實質上,它們是一組模型。

另外,爲了清楚起見,我只需要這些「東西」的模型。他們都將與一個人模型相關聯,他們將以這種方式訪問​​。所以我不打算爲他們中的任何人設置控制員或觀點。

+0

您是否考慮將它們定義爲'events'和'句號'併爲「type_of_thing」添加一列,然後您可以調用'TimelineObject.events'或'TimelineObject.periods'或者更好的方法是使用'by_person'作用域TimelineObject .by_person(person).events' – engineersmnky

回答

2

如何創建Rails的

STI關係,假設我們有一個模型計算機

class Computer < ActiveRecord:Base 
    # in app/models 
    # Fields: 
    # String name 
    # String owner 
    # String manafacturer 
    # String color 

    def default_browser 
    "unknown!" 
    end 
end 

現在,我們希望Mac和PC之間進行區分。爲每個表做一個不同的表是沒有意義的,因爲它們都有幾乎相同的列。相反,我們可以創建一個新的列,類型,它告訴Rails在計算機上使用STI。讓我們看看模型的外觀。

class Computer < ActiveRecord:Base 
    # in app/models 
    # Fields: 
    # String name 
    # String owner 
    # String manafacturer 
    # String color 
    # String type 

    def default_browser 
    "unknown!" 
    end 
end 

class Mac < Computer 
    # in app/models 
    # this is for Computers with type="Mac" 
    before_save :set_color 

    # Lets say all macs are silver, no point setting these ourselves 
    def set_color 
    self.color = "silver" 
    self.manafacturer = "apple" 
    end 

    # Lets overwrite the default_browser method 
    def default_browser 
    "safari" 
    end 
end 

class PC < Computer 
    # in app/models 

    # Lets overwrite the default_browser method 
    def default_browser 
    "ie =(" 
    end 
end 

任何時候Rails打開計算機對象,它會查找與類型相對應的子類。例如,鍵入=「CoolComputer」對應於型號CoolComputer <計算機。

如何使用STI模式

要創建一個新的MAC,你可以這樣做:

m = Mac.new 
m.name = "kunal's mac" 
m.owner = "kunal" 
m.save 
m # => #<Mac id: 1, name: "kunal's mac", owner: "kunal", manafacturer: "apple", color: "silver", type: "Mac", ...> 

請告訴我更酷的是ActiveRecord的查詢。讓我們說我們想要所有的電腦

Computer.all # => [#<Mac id: 1, name: "kunal's mac", owner: "kunal", manafacturer: "apple", color: "silver", type: "Mac", ...>, #<Mac id: 2, name: "anuj's mac", owner: "anuj", manafacturer: "apple", color: "silver", type: "Mac", ...>, #<PC id: 3, name: "bob's pc", owner: "bob", manafacturer: "toshiba", color: "blue", type: "PC", ...>] 

是的,它會自動給你正確的對象!你可以通過調用.type,is_a來找出特定對象的類型。或的.class

Computer.first.type == MaC# true 
Computer.first.is_a? MaC# true 
Computer.first.class == MaC# true 

如果我們只希望蘋果電腦,我們可以做

Mac.all 

自定義繼承列

如果您想使用另一列而不是類型用於STI,您可以簡單地將此添加到您的型號頂部:

set_inheritance_column 'whatever_you want' 

注意:如果您有一個名爲type的數據庫列,可以通過將繼承列更改爲非type類型來關閉Single Table Inheritance。

Rails中

組織這次使用STI之後,我結束了臃腫的模型文件夾,因爲所有的許多自定義子模型的創建我是在模型文件夾中。爲了解決這個問題,我在模型中創建的文件夾來存儲所有我的電腦的具體型號

* app 
* models 
*  computer.rb 
*  computers 
*  pc.rb 
*  mac.rb 

Rails沒有自動打開子文件夾中的文件夾模式,所以我的config/application.rb中加入:

# Load Subfolder Models 
config.autoload_paths += Dir[Rails.root.join('app', 'models', '{**}')] 
+0

Jack,這將如何影響應用程序從'views'/表單的立場?即如果你使用STI,你不需要有兩個'new.html.erb'頁面...一個用於創建Mac和一個用於創建PC?或者你可以結合成一個形式與下拉選擇器來選擇MAC或PC? (對不起,我的意思不是減損Oddity的問題......但是認爲你的答案可能有助於決定他是否也去S/STI)...... thx, – BB500

+0

這可以使用'nested resource'gem – jimagic

+0

感謝您從這裏複製粘貼:http://blog.thirst.co/post/14885390861/rails-single-table-inheritance這仍然不能說服我,如果性傳播感染是一個很好的方式去與此。就像我在問題中所說的那樣,會有一些共同的屬性,但其中許多屬性並不常見。這好像會在表格中創建大量浪費的列空間,不是嗎? – dkniffin