在Rails迁移中将外键也设为主键

4

编辑:

我希望将一列视为Rails中的主键和外键。也就是说,使用references方法创建一个外键。我想要做的事情类似于:

def change
  create_table :VipPerson, id: false do |t|
    t.primary_key :person_id
    t.references :person, :id, column: :person_id

    t.timestamps
  end
end

我希望拥有一个定制化的主键,该主键也被Rails模型用于指向Person模型(见下文)。这与数据库中使用的外键无关(直到Rails 4.2才支持创建真正的外键,如Demi Magus所指出的)。

-

我想在我的Rails项目中实现多表继承(MTI),因此实现类似于关系数据库中通常所做的继承:

table: Person
-------------
(PK) ID
Name
...

table: VipPerson (specalization of Person)
----------------
(PK) (FK) Person_ID
VIP-Status
...

因此,我需要编写一个迁移,将一个属性(这里是Person_ID)同时声明为(自定义的)主键和外键。 我不知道如何使用Rails迁移DSP的方法来做到这一点。
我不想使用Rails的多态关联,因为我想保证数据库中的数据完整性。我知道我还需要自定义Rails模型,但让我们不要谈论那个话题。 主要问题是如何编写迁移,使PK也成为FK(反之亦然)。
2个回答

2

外键关系仅适用于最新版本的Rails,即4.2,您可以在发布说明中查看,您可以像这样使用它:

创建一个简单的外键:

add_foreign_key :articles, :authors

生成:

ALTER TABLE "articles" ADD CONSTRAINT articles_author_id_fk FOREIGN KEY ("author_id") REFERENCES "authors" ("id")

你也应该知道,add_foreign_key 只会生成一个外键约束,而不会像 activerecord 的 add_column 一样生成列。
add_column :articles, :author_id, :integer

将生成:

ALTER TABLE "articles" ADD COLUMN author_id INT(11);

你可以在这里找到更多信息。
此外,如果你不仅仅寻求Rails的优势,那么你可能会发现这个gem很有用,它允许你做你想做的事情,也就是composite_primary_keys,唯一需要注意的是你必须使用与你的rails版本兼容的版本。
希望能对你有所帮助:D

如果你在文档中没有找到相关内容,那么很可能你所寻找的功能是无法实现的。另外,最新版本的Rails发布才一个月左右,因此要找到专家可能比较困难。如果你觉得我的回答有用的话,希望能给我点个赞 :D。祝好运 ;D - Demi Magus
抱歉如果我的表述可能会误导您。我的问题实际上不仅限于最新版本的Rails。事实上,这个问题适用于ActiveRecord的开始。像这样的数据库结构是一个常见情况,并且早在Rails出现之前就已经存在了。我并不真正相信没有解决方案,因为像这样的场景相当普遍。 P.S. 我的声望还太低,无法投票。Q___Q - ZeroMax
别担心XD。在这种情况下,我听说有一些宝石可以解决这个问题,也许这个链接对你有帮助 https://github.com/composite-primary-keys/composite_primary_keys - Demi Magus
是的,我知道这会有所帮助。但它总是需要跟上Rails版本。 事实证明,有一种本地方法,但它需要在模型端进行一些定制,而不是在迁移中进行。我会发布一个答案。 - ZeroMax
1
实际上,当您还想要保证引用完整性时,您的答案是我答案的完美补充。 :) - ZeroMax
显示剩余2条评论

2
解决方法是在模型中手动设置主键和外键,而不是在迁移中调整(注意必须告诉Rails不要创建默认的id列,通过在选项中传递“id: false”来实现):
迁移文件:
def change
  create_table :VipPerson, id: false do |t|
    t.primary_key :person_id  # Normal integer PK, shouldn't auto-increment
    t.integer :vip_status
    ..... etc.
  end
end

在这个模型中:
class VipPerson < ActiveRecord::Base
  self.primary_key = "person_id"
  belongs_to :person, foreign_key: "person_id"
end

只需手动指向模型中的同一列。在数据库层面上,您可以使用真正的外键约束来进一步增强主键(请参见Demi Magus的答案)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接