2014-08-31 51 views
1

假设我创建一个简单的特性的模型:(Rails)我如何绕过STI空字段?

class CreateWingedThings < ActiveRecord::Migration 
    create_table :winged_things do 
    t.integer :number_of_wings 
    t.integer :species 
    t.integer :air_speed_velocity 
    t.boolean :laden, :default => false 
    end 
end 

但现在我想两种特定类型的WingedThing,用自己鲜明的特点:

class CreateBats < ActiveRecord::Migration 
    create_table :bats do 
    t.integer :echolocation_volume 
    t.string :snout_type 
    end 
end 

class CreateBirds < ActiveRecord::Migration 
    create_table :birds do 
    t.string :beak_size 
    t.integer :number_of_feathers 
    end 
end 

这是一个很简单的事做STI - 有BatBird继承WingedThing

class Bat < WingedThing 

(奖金问题:这在数据库中看起来如何?我每Bat和每个Bird生成WingedThing行吗?这是我的理解,但请纠正我,如果我错了。)

(从这可能错误的理解)但是,如果我想要,如果FlightlessBirdair_speed_velocity将是一个毫无意义的领域,它的负担将是不道德的; FlightlessBird的所有实例都将在为相应的WingedThing生成的DB行中包含空值条目ladenair_speed_velocity。这是比我需要的更多的数据,并不适合可扩展性,但我也不想完全删除这些字段,因为至少有两个其他模型依赖于它们。

TL;博士我想什么,能够做的是有BirdBat能够访问两者共同的特点,同时具有FlightlessBird同父表,但没有产生一些特性数据库中的空字段。

建模这样的关系的最佳方式是什么,以确保我可以获得最薄的数据库?

+0

为什么migrations从'ActiveRecord :: Base'而不是从'ActiveRecord :: Migration'继承? – mdesantis 2014-08-31 15:19:43

+0

好问题。固定。 – Vardarac 2014-08-31 15:21:06

回答

2

首先,对于STI,您不会为每个子类创建额外的表 - 您的蝙蝠/鸟表不会被使用。

其次空列通常非常轻量级。例如在postgres中,它们在每行上都有一个掩码,表示哪些列为空。位掩码指示哪些列都存在,因此增加一个空列只会增加每行1位(撇开一些围捕微妙之处)

你基本上有4种选择:

  • 不使用STI(即每个模型一个表格,以及每个模型的所有属性)。你仍然可以有一个共同的基类(它必须具有“自我”。abstract_class = TRUE)对于任何共享代码

  • 使用STI,一些列未使用的一些子类

  • 使用STI,但有你的子类必须使用具有针对特定子类的额外列的表has_one关系

  • 连载非共享的属性(即尽可能的DB而言它们都具有相同的属性)

有有效的CA为所有这些寻找答案 - 他们也有缺点。例如,如果您沿着可能找到的has_one路线走下去,取决于使用情况,您对额外表格有很多查询。另一方面,如果你很少使用额外的属性,那就太棒了。

虽然我真的不会出汗一些空列 - 你不可能注意到。